Coverage Report

Created: 2025-05-27 15:32

/mnt/user-data/adam/aztec-packages/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp
Line
Count
Source (jump to first uncovered line)
1
// === AUDIT STATUS ===
2
// internal:    { status: not started, auditors: [], date: YYYY-MM-DD }
3
// external_1:  { status: not started, auditors: [], date: YYYY-MM-DD }
4
// external_2:  { status: not started, auditors: [], date: YYYY-MM-DD }
5
// =====================
6
7
#pragma once
8
9
#include "barretenberg/common/assert.hpp"
10
#include "barretenberg/common/zip_view.hpp"
11
#include "barretenberg/numeric/uint256/uint256.hpp"
12
#include "barretenberg/numeric/uintx/uintx.hpp"
13
#include <tuple>
14
15
#include "../circuit_builders/circuit_builders.hpp"
16
#include "bigfield.hpp"
17
18
#include "../bit_array/bit_array.hpp"
19
#include "../field/field.hpp"
20
#include "barretenberg/transcript/origin_tag.hpp"
21
22
namespace bb::stdlib {
23
24
template <typename Builder, typename T>
25
bigfield<Builder, T>::bigfield(Builder* parent_context)
26
    : context(parent_context)
27
    , binary_basis_limbs{ Limb(bb::fr(0)), Limb(bb::fr(0)), Limb(bb::fr(0)), Limb(bb::fr(0)) }
28
    , prime_basis_limb(context, 0)
29
8.96M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_
Line
Count
Source
29
8.28M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_
Line
Count
Source
29
1.23k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_
Line
Count
Source
29
130
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EPS4_
Line
Count
Source
29
31.9k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EPS4_
Line
Count
Source
29
279
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EPS6_
Line
Count
Source
29
549k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EPS6_
Line
Count
Source
29
4.44k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EPS4_
Line
Count
Source
29
53.0k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EPS4_
Line
Count
Source
29
115
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EPS6_
Line
Count
Source
29
42.4k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EPS6_
Line
Count
Source
29
92
{}
30
31
template <typename Builder, typename T>
32
bigfield<Builder, T>::bigfield(Builder* parent_context, const uint256_t& value)
33
    : context(parent_context)
34
    , binary_basis_limbs{ Limb(bb::fr(value.slice(0, NUM_LIMB_BITS))),
35
                          Limb(bb::fr(value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2))),
36
                          Limb(bb::fr(value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3))),
37
                          Limb(bb::fr(value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4))) }
38
    , prime_basis_limb(context, value)
39
2.65M
{
40
2.65M
    ASSERT(value < modulus);
41
2.65M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
2.41M
{
40
2.41M
    ASSERT(value < modulus);
41
2.41M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
824
{
40
824
    ASSERT(value < modulus);
41
824
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
75
{
40
75
    ASSERT(value < modulus);
41
75
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_RKNS_7numeric9uint256_tE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
10.9k
{
40
10.9k
    ASSERT(value < modulus);
41
10.9k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
168
{
40
168
    ASSERT(value < modulus);
41
168
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
192k
{
40
192k
    ASSERT(value < modulus);
41
192k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
2.62k
{
40
2.62k
    ASSERT(value < modulus);
41
2.62k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
16.0k
{
40
16.0k
    ASSERT(value < modulus);
41
16.0k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
103
{
40
103
    ASSERT(value < modulus);
41
103
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
12.8k
{
40
12.8k
    ASSERT(value < modulus);
41
12.8k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
84
{
40
84
    ASSERT(value < modulus);
41
84
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_RKNS_7numeric9uint256_tE
42
43
// TODO(https://github.com/AztecProtocol/barretenberg/issues/850): audit the evaluate_linear_identity function
44
template <typename Builder, typename T>
45
bigfield<Builder, T>::bigfield(const field_t<Builder>& low_bits_in,
46
                               const field_t<Builder>& high_bits_in,
47
                               const bool can_overflow,
48
                               const size_t maximum_bitlength)
49
45.5k
{
50
45.5k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
45.5k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
0
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
45.5k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
45.5k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
45.5k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
0
    field_t<Builder> limb_0(context);
60
0
    field_t<Builder> limb_1(context);
61
0
    field_t<Builder> limb_2(context);
62
0
    field_t<Builder> limb_3(context);
63
45.5k
    if (!low_bits_in.is_constant()) {
64
45.1k
        std::vector<uint32_t> low_accumulator;
65
45.1k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
45.1k
            const auto limb_witnesses =
68
45.1k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
45.1k
            limb_0.witness_index = limb_witnesses[0];
70
45.1k
            limb_1.witness_index = limb_witnesses[1];
71
45.1k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
45.1k
        } else {
84
45.1k
            size_t mid_index;
85
45.1k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
45.1k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
45.1k
                                                                         "bigfield: low_bits_in too large.");
88
45.1k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
45.1k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
45.1k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
45.1k
        }
95
45.1k
    } else {
96
378
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
378
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
378
        limb_0 = field_t(context, bb::fr(slice_0));
99
378
        limb_1 = field_t(context, bb::fr(slice_1));
100
378
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
45.5k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
45.5k
    if (maximum_bitlength > 0) {
109
446
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
0
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
45.5k
    if (!high_bits_in.is_constant()) {
115
116
45.1k
        std::vector<uint32_t> high_accumulator;
117
45.1k
        if constexpr (HasPlookup<Builder>) {
118
45.1k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
45.1k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
45.1k
            limb_2.witness_index = limb_witnesses[0];
121
45.1k
            limb_3.witness_index = limb_witnesses[1];
122
45.1k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
45.1k
        } else {
125
45.1k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
45.1k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
45.1k
                                                                          "bigfield: high_bits_in too large.");
128
129
45.1k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
45.1k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
45.1k
        }
132
45.1k
    } else {
133
378
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
378
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
378
        limb_2 = field_t(context, bb::fr(slice_2));
136
378
        limb_3 = field_t(context, bb::fr(slice_3));
137
378
    }
138
0
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
0
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
0
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
45.5k
    if (maximum_bitlength > 0) {
142
446
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
446
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
45.1k
    } else {
145
45.1k
        binary_basis_limbs[3] =
146
45.1k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
45.1k
    }
148
0
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
0
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
0
    set_origin_tag(new_tag);
151
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Line
Count
Source
49
37.5k
{
50
37.5k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
37.5k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
37.5k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
37.5k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
37.5k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
37.5k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
37.5k
    field_t<Builder> limb_0(context);
60
37.5k
    field_t<Builder> limb_1(context);
61
37.5k
    field_t<Builder> limb_2(context);
62
37.5k
    field_t<Builder> limb_3(context);
63
37.5k
    if (!low_bits_in.is_constant()) {
64
37.5k
        std::vector<uint32_t> low_accumulator;
65
37.5k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
37.5k
            const auto limb_witnesses =
68
37.5k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
37.5k
            limb_0.witness_index = limb_witnesses[0];
70
37.5k
            limb_1.witness_index = limb_witnesses[1];
71
37.5k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
37.5k
        } else {
84
37.5k
            size_t mid_index;
85
37.5k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
37.5k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
37.5k
                                                                         "bigfield: low_bits_in too large.");
88
37.5k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
37.5k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
37.5k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
37.5k
        }
95
37.5k
    } else {
96
9
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
9
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
9
        limb_0 = field_t(context, bb::fr(slice_0));
99
9
        limb_1 = field_t(context, bb::fr(slice_1));
100
9
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
37.5k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
37.5k
    if (maximum_bitlength > 0) {
109
106
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
106
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
106
    }
112
    // We create the high limb values similar to the low limb ones above
113
37.5k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
37.5k
    if (!high_bits_in.is_constant()) {
115
116
37.5k
        std::vector<uint32_t> high_accumulator;
117
37.5k
        if constexpr (HasPlookup<Builder>) {
118
37.5k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
37.5k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
37.5k
            limb_2.witness_index = limb_witnesses[0];
121
37.5k
            limb_3.witness_index = limb_witnesses[1];
122
37.5k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
37.5k
        } else {
125
37.5k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
37.5k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
37.5k
                                                                          "bigfield: high_bits_in too large.");
128
129
37.5k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
37.5k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
37.5k
        }
132
37.5k
    } else {
133
9
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
9
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
9
        limb_2 = field_t(context, bb::fr(slice_2));
136
9
        limb_3 = field_t(context, bb::fr(slice_3));
137
9
    }
138
37.5k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
37.5k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
37.5k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
37.5k
    if (maximum_bitlength > 0) {
142
106
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
106
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
37.4k
    } else {
145
37.4k
        binary_basis_limbs[3] =
146
37.4k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
37.4k
    }
148
37.5k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
37.5k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
37.5k
    set_origin_tag(new_tag);
151
37.5k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Line
Count
Source
49
1.29k
{
50
1.29k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
1.29k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
1.29k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
1.29k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
1.29k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
1.29k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
1.29k
    field_t<Builder> limb_0(context);
60
1.29k
    field_t<Builder> limb_1(context);
61
1.29k
    field_t<Builder> limb_2(context);
62
1.29k
    field_t<Builder> limb_3(context);
63
1.29k
    if (!low_bits_in.is_constant()) {
64
1.29k
        std::vector<uint32_t> low_accumulator;
65
1.29k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
1.29k
            const auto limb_witnesses =
68
1.29k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
1.29k
            limb_0.witness_index = limb_witnesses[0];
70
1.29k
            limb_1.witness_index = limb_witnesses[1];
71
1.29k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
1.29k
        } else {
84
1.29k
            size_t mid_index;
85
1.29k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
1.29k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
1.29k
                                                                         "bigfield: low_bits_in too large.");
88
1.29k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
1.29k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
1.29k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
1.29k
        }
95
1.29k
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
1.29k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
1.29k
    if (maximum_bitlength > 0) {
109
322
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
322
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
322
    }
112
    // We create the high limb values similar to the low limb ones above
113
1.29k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
1.29k
    if (!high_bits_in.is_constant()) {
115
116
1.29k
        std::vector<uint32_t> high_accumulator;
117
1.29k
        if constexpr (HasPlookup<Builder>) {
118
1.29k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
1.29k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
1.29k
            limb_2.witness_index = limb_witnesses[0];
121
1.29k
            limb_3.witness_index = limb_witnesses[1];
122
1.29k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
1.29k
        } else {
125
1.29k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
1.29k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
1.29k
                                                                          "bigfield: high_bits_in too large.");
128
129
1.29k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
1.29k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
1.29k
        }
132
1.29k
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
1.29k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
1.29k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
1.29k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
1.29k
    if (maximum_bitlength > 0) {
142
322
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
322
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
971
    } else {
145
971
        binary_basis_limbs[3] =
146
971
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
971
    }
148
1.29k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
1.29k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
1.29k
    set_origin_tag(new_tag);
151
1.29k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS6_EESC_bm
Line
Count
Source
49
2.20k
{
50
2.20k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
2.20k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
2.20k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
2.20k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
2.20k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
2.20k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
2.20k
    field_t<Builder> limb_0(context);
60
2.20k
    field_t<Builder> limb_1(context);
61
2.20k
    field_t<Builder> limb_2(context);
62
2.20k
    field_t<Builder> limb_3(context);
63
2.20k
    if (!low_bits_in.is_constant()) {
64
2.19k
        std::vector<uint32_t> low_accumulator;
65
2.19k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
2.19k
            const auto limb_witnesses =
68
2.19k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
2.19k
            limb_0.witness_index = limb_witnesses[0];
70
2.19k
            limb_1.witness_index = limb_witnesses[1];
71
2.19k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
2.19k
        } else {
84
2.19k
            size_t mid_index;
85
2.19k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
2.19k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
2.19k
                                                                         "bigfield: low_bits_in too large.");
88
2.19k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
2.19k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
2.19k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
2.19k
        }
95
2.19k
    } else {
96
9
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
9
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
9
        limb_0 = field_t(context, bb::fr(slice_0));
99
9
        limb_1 = field_t(context, bb::fr(slice_1));
100
9
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
2.20k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
2.20k
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
2.20k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
2.20k
    if (!high_bits_in.is_constant()) {
115
116
2.19k
        std::vector<uint32_t> high_accumulator;
117
2.19k
        if constexpr (HasPlookup<Builder>) {
118
2.19k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
2.19k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
2.19k
            limb_2.witness_index = limb_witnesses[0];
121
2.19k
            limb_3.witness_index = limb_witnesses[1];
122
2.19k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
2.19k
        } else {
125
2.19k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
2.19k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
2.19k
                                                                          "bigfield: high_bits_in too large.");
128
129
2.19k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
2.19k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
2.19k
        }
132
2.19k
    } else {
133
9
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
9
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
9
        limb_2 = field_t(context, bb::fr(slice_2));
136
9
        limb_3 = field_t(context, bb::fr(slice_3));
137
9
    }
138
2.20k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
2.20k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
2.20k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
2.20k
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
2.20k
    } else {
145
2.20k
        binary_basis_limbs[3] =
146
2.20k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
2.20k
    }
148
2.20k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
2.20k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
2.20k
    set_origin_tag(new_tag);
151
2.20k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_7field_tIS6_EESB_bm
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
166
{
50
166
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
166
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
166
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
166
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
166
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
166
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
166
    field_t<Builder> limb_0(context);
60
166
    field_t<Builder> limb_1(context);
61
166
    field_t<Builder> limb_2(context);
62
166
    field_t<Builder> limb_3(context);
63
166
    if (!low_bits_in.is_constant()) {
64
160
        std::vector<uint32_t> low_accumulator;
65
160
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
160
            const auto limb_witnesses =
68
160
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
160
            limb_0.witness_index = limb_witnesses[0];
70
160
            limb_1.witness_index = limb_witnesses[1];
71
160
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
160
        } else {
84
160
            size_t mid_index;
85
160
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
160
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
160
                                                                         "bigfield: low_bits_in too large.");
88
160
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
160
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
160
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
160
        }
95
160
    } else {
96
6
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
6
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
6
        limb_0 = field_t(context, bb::fr(slice_0));
99
6
        limb_1 = field_t(context, bb::fr(slice_1));
100
6
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
166
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
166
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
166
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
166
    if (!high_bits_in.is_constant()) {
115
116
160
        std::vector<uint32_t> high_accumulator;
117
160
        if constexpr (HasPlookup<Builder>) {
118
160
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
160
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
160
            limb_2.witness_index = limb_witnesses[0];
121
160
            limb_3.witness_index = limb_witnesses[1];
122
160
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
160
        } else {
125
160
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
160
                                                                          static_cast<size_t>(num_high_limb_bits),
127
160
                                                                          "bigfield: high_bits_in too large.");
128
129
160
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
160
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
160
        }
132
160
    } else {
133
6
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
6
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
6
        limb_2 = field_t(context, bb::fr(slice_2));
136
6
        limb_3 = field_t(context, bb::fr(slice_3));
137
6
    }
138
166
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
166
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
166
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
166
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
166
    } else {
145
166
        binary_basis_limbs[3] =
146
166
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
166
    }
148
166
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
166
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
166
    set_origin_tag(new_tag);
151
166
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
72
{
50
72
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
72
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
72
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
72
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
72
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
72
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
72
    field_t<Builder> limb_0(context);
60
72
    field_t<Builder> limb_1(context);
61
72
    field_t<Builder> limb_2(context);
62
72
    field_t<Builder> limb_3(context);
63
72
    if (!low_bits_in.is_constant()) {
64
60
        std::vector<uint32_t> low_accumulator;
65
60
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
60
            const auto limb_witnesses =
68
60
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
60
            limb_0.witness_index = limb_witnesses[0];
70
60
            limb_1.witness_index = limb_witnesses[1];
71
60
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
60
        } else {
84
60
            size_t mid_index;
85
60
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
60
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
60
                                                                         "bigfield: low_bits_in too large.");
88
60
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
60
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
60
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
60
        }
95
60
    } else {
96
12
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
12
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
12
        limb_0 = field_t(context, bb::fr(slice_0));
99
12
        limb_1 = field_t(context, bb::fr(slice_1));
100
12
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
72
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
72
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
72
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
72
    if (!high_bits_in.is_constant()) {
115
116
60
        std::vector<uint32_t> high_accumulator;
117
60
        if constexpr (HasPlookup<Builder>) {
118
60
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
60
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
60
            limb_2.witness_index = limb_witnesses[0];
121
60
            limb_3.witness_index = limb_witnesses[1];
122
60
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
60
        } else {
125
60
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
60
                                                                          static_cast<size_t>(num_high_limb_bits),
127
60
                                                                          "bigfield: high_bits_in too large.");
128
129
60
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
60
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
60
        }
132
60
    } else {
133
12
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
12
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
12
        limb_2 = field_t(context, bb::fr(slice_2));
136
12
        limb_3 = field_t(context, bb::fr(slice_3));
137
12
    }
138
72
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
72
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
72
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
72
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
72
    } else {
145
72
        binary_basis_limbs[3] =
146
72
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
72
    }
148
72
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
72
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
72
    set_origin_tag(new_tag);
151
72
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Line
Count
Source
49
2.96k
{
50
2.96k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
2.96k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
2.96k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
2.96k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
2.96k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
2.96k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
2.96k
    field_t<Builder> limb_0(context);
60
2.96k
    field_t<Builder> limb_1(context);
61
2.96k
    field_t<Builder> limb_2(context);
62
2.96k
    field_t<Builder> limb_3(context);
63
2.96k
    if (!low_bits_in.is_constant()) {
64
2.85k
        std::vector<uint32_t> low_accumulator;
65
2.85k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
2.85k
            const auto limb_witnesses =
68
2.85k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
2.85k
            limb_0.witness_index = limb_witnesses[0];
70
2.85k
            limb_1.witness_index = limb_witnesses[1];
71
2.85k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
2.85k
        } else {
84
2.85k
            size_t mid_index;
85
2.85k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
2.85k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
2.85k
                                                                         "bigfield: low_bits_in too large.");
88
2.85k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
2.85k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
2.85k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
2.85k
        }
95
2.85k
    } else {
96
114
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
114
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
114
        limb_0 = field_t(context, bb::fr(slice_0));
99
114
        limb_1 = field_t(context, bb::fr(slice_1));
100
114
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
2.96k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
2.96k
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
2.96k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
2.96k
    if (!high_bits_in.is_constant()) {
115
116
2.85k
        std::vector<uint32_t> high_accumulator;
117
2.85k
        if constexpr (HasPlookup<Builder>) {
118
2.85k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
2.85k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
2.85k
            limb_2.witness_index = limb_witnesses[0];
121
2.85k
            limb_3.witness_index = limb_witnesses[1];
122
2.85k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
2.85k
        } else {
125
2.85k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
2.85k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
2.85k
                                                                          "bigfield: high_bits_in too large.");
128
129
2.85k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
2.85k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
2.85k
        }
132
2.85k
    } else {
133
114
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
114
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
114
        limb_2 = field_t(context, bb::fr(slice_2));
136
114
        limb_3 = field_t(context, bb::fr(slice_3));
137
114
    }
138
2.96k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
2.96k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
2.96k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
2.96k
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
2.96k
    } else {
145
2.96k
        binary_basis_limbs[3] =
146
2.96k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
2.96k
    }
148
2.96k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
2.96k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
2.96k
    set_origin_tag(new_tag);
151
2.96k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Line
Count
Source
49
1.14k
{
50
1.14k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
1.14k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
1.14k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
1.14k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
1.14k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
1.14k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
1.14k
    field_t<Builder> limb_0(context);
60
1.14k
    field_t<Builder> limb_1(context);
61
1.14k
    field_t<Builder> limb_2(context);
62
1.14k
    field_t<Builder> limb_3(context);
63
1.14k
    if (!low_bits_in.is_constant()) {
64
912
        std::vector<uint32_t> low_accumulator;
65
912
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
912
            const auto limb_witnesses =
68
912
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
912
            limb_0.witness_index = limb_witnesses[0];
70
912
            limb_1.witness_index = limb_witnesses[1];
71
912
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
912
        } else {
84
912
            size_t mid_index;
85
912
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
912
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
912
                                                                         "bigfield: low_bits_in too large.");
88
912
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
912
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
912
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
912
        }
95
912
    } else {
96
228
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
228
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
228
        limb_0 = field_t(context, bb::fr(slice_0));
99
228
        limb_1 = field_t(context, bb::fr(slice_1));
100
228
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
1.14k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
1.14k
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
1.14k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
1.14k
    if (!high_bits_in.is_constant()) {
115
116
912
        std::vector<uint32_t> high_accumulator;
117
912
        if constexpr (HasPlookup<Builder>) {
118
912
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
912
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
912
            limb_2.witness_index = limb_witnesses[0];
121
912
            limb_3.witness_index = limb_witnesses[1];
122
912
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
912
        } else {
125
912
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
912
                                                                          static_cast<size_t>(num_high_limb_bits),
127
912
                                                                          "bigfield: high_bits_in too large.");
128
129
912
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
912
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
912
        }
132
912
    } else {
133
228
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
228
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
228
        limb_2 = field_t(context, bb::fr(slice_2));
136
228
        limb_3 = field_t(context, bb::fr(slice_3));
137
228
    }
138
1.14k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
1.14k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
1.14k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
1.14k
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
1.14k
    } else {
145
1.14k
        binary_basis_limbs[3] =
146
1.14k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
1.14k
    }
148
1.14k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
1.14k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
1.14k
    set_origin_tag(new_tag);
151
1.14k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
45
{
50
45
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
45
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
45
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
45
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
45
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
45
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
45
    field_t<Builder> limb_0(context);
60
45
    field_t<Builder> limb_1(context);
61
45
    field_t<Builder> limb_2(context);
62
45
    field_t<Builder> limb_3(context);
63
45
    if (!low_bits_in.is_constant()) {
64
45
        std::vector<uint32_t> low_accumulator;
65
45
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
45
            const auto limb_witnesses =
68
45
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
45
            limb_0.witness_index = limb_witnesses[0];
70
45
            limb_1.witness_index = limb_witnesses[1];
71
45
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
45
        } else {
84
45
            size_t mid_index;
85
45
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
45
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
45
                                                                         "bigfield: low_bits_in too large.");
88
45
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
45
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
45
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
45
        }
95
45
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
45
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
45
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
45
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
45
    if (!high_bits_in.is_constant()) {
115
116
45
        std::vector<uint32_t> high_accumulator;
117
45
        if constexpr (HasPlookup<Builder>) {
118
45
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
45
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
45
            limb_2.witness_index = limb_witnesses[0];
121
45
            limb_3.witness_index = limb_witnesses[1];
122
45
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
45
        } else {
125
45
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
45
                                                                          static_cast<size_t>(num_high_limb_bits),
127
45
                                                                          "bigfield: high_bits_in too large.");
128
129
45
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
45
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
45
        }
132
45
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
45
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
45
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
45
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
45
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
45
    } else {
145
45
        binary_basis_limbs[3] =
146
45
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
45
    }
148
45
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
45
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
45
    set_origin_tag(new_tag);
151
45
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
50
{
50
50
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
50
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
50
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
50
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
50
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
50
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
50
    field_t<Builder> limb_0(context);
60
50
    field_t<Builder> limb_1(context);
61
50
    field_t<Builder> limb_2(context);
62
50
    field_t<Builder> limb_3(context);
63
50
    if (!low_bits_in.is_constant()) {
64
50
        std::vector<uint32_t> low_accumulator;
65
50
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
50
            const auto limb_witnesses =
68
50
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
50
            limb_0.witness_index = limb_witnesses[0];
70
50
            limb_1.witness_index = limb_witnesses[1];
71
50
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
50
        } else {
84
50
            size_t mid_index;
85
50
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
50
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
50
                                                                         "bigfield: low_bits_in too large.");
88
50
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
50
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
50
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
50
        }
95
50
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
50
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
50
    if (maximum_bitlength > 0) {
109
10
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
10
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
10
    }
112
    // We create the high limb values similar to the low limb ones above
113
50
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
50
    if (!high_bits_in.is_constant()) {
115
116
50
        std::vector<uint32_t> high_accumulator;
117
50
        if constexpr (HasPlookup<Builder>) {
118
50
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
50
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
50
            limb_2.witness_index = limb_witnesses[0];
121
50
            limb_3.witness_index = limb_witnesses[1];
122
50
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
50
        } else {
125
50
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
50
                                                                          static_cast<size_t>(num_high_limb_bits),
127
50
                                                                          "bigfield: high_bits_in too large.");
128
129
50
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
50
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
50
        }
132
50
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
50
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
50
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
50
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
50
    if (maximum_bitlength > 0) {
142
10
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
10
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
40
    } else {
145
40
        binary_basis_limbs[3] =
146
40
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
40
    }
148
50
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
50
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
50
    set_origin_tag(new_tag);
151
50
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Line
Count
Source
49
36
{
50
36
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
36
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
36
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
36
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
36
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
36
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
36
    field_t<Builder> limb_0(context);
60
36
    field_t<Builder> limb_1(context);
61
36
    field_t<Builder> limb_2(context);
62
36
    field_t<Builder> limb_3(context);
63
36
    if (!low_bits_in.is_constant()) {
64
36
        std::vector<uint32_t> low_accumulator;
65
36
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
36
            const auto limb_witnesses =
68
36
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
36
            limb_0.witness_index = limb_witnesses[0];
70
36
            limb_1.witness_index = limb_witnesses[1];
71
36
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
36
        } else {
84
36
            size_t mid_index;
85
36
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
36
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
36
                                                                         "bigfield: low_bits_in too large.");
88
36
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
36
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
36
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
36
        }
95
36
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
36
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
36
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
36
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
36
    if (!high_bits_in.is_constant()) {
115
116
36
        std::vector<uint32_t> high_accumulator;
117
36
        if constexpr (HasPlookup<Builder>) {
118
36
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
36
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
36
            limb_2.witness_index = limb_witnesses[0];
121
36
            limb_3.witness_index = limb_witnesses[1];
122
36
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
36
        } else {
125
36
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
36
                                                                          static_cast<size_t>(num_high_limb_bits),
127
36
                                                                          "bigfield: high_bits_in too large.");
128
129
36
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
36
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
36
        }
132
36
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
36
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
36
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
36
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
36
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
36
    } else {
145
36
        binary_basis_limbs[3] =
146
36
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
36
    }
148
36
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
36
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
36
    set_origin_tag(new_tag);
151
36
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Line
Count
Source
49
40
{
50
40
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
40
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
40
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
40
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
40
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
40
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
40
    field_t<Builder> limb_0(context);
60
40
    field_t<Builder> limb_1(context);
61
40
    field_t<Builder> limb_2(context);
62
40
    field_t<Builder> limb_3(context);
63
40
    if (!low_bits_in.is_constant()) {
64
40
        std::vector<uint32_t> low_accumulator;
65
40
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
40
            const auto limb_witnesses =
68
40
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
40
            limb_0.witness_index = limb_witnesses[0];
70
40
            limb_1.witness_index = limb_witnesses[1];
71
40
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
40
        } else {
84
40
            size_t mid_index;
85
40
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
40
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
40
                                                                         "bigfield: low_bits_in too large.");
88
40
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
40
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
40
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
40
        }
95
40
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
40
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
40
    if (maximum_bitlength > 0) {
109
8
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
8
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
8
    }
112
    // We create the high limb values similar to the low limb ones above
113
40
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
40
    if (!high_bits_in.is_constant()) {
115
116
40
        std::vector<uint32_t> high_accumulator;
117
40
        if constexpr (HasPlookup<Builder>) {
118
40
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
40
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
40
            limb_2.witness_index = limb_witnesses[0];
121
40
            limb_3.witness_index = limb_witnesses[1];
122
40
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
40
        } else {
125
40
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
40
                                                                          static_cast<size_t>(num_high_limb_bits),
127
40
                                                                          "bigfield: high_bits_in too large.");
128
129
40
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
40
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
40
        }
132
40
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
40
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
40
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
40
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
40
    if (maximum_bitlength > 0) {
142
8
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
8
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
32
    } else {
145
32
        binary_basis_limbs[3] =
146
32
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
32
    }
148
40
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
40
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
40
    set_origin_tag(new_tag);
151
40
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS6_EESC_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_7field_tIS6_EESB_bm
152
153
template <typename Builder, typename T>
154
bigfield<Builder, T>::bigfield(const bigfield& other)
155
    : context(other.context)
156
    , binary_basis_limbs{ other.binary_basis_limbs[0],
157
                          other.binary_basis_limbs[1],
158
                          other.binary_basis_limbs[2],
159
                          other.binary_basis_limbs[3] }
160
    , prime_basis_limb(other.prime_basis_limb)
161
21.0M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKS6_
Line
Count
Source
161
19.2M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKS6_
Line
Count
Source
161
3.42k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKS8_
Line
Count
Source
161
110
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKS7_
Line
Count
Source
161
79.2k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKS7_
Line
Count
Source
161
520
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKS9_
Line
Count
Source
161
1.38M
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKS9_
Line
Count
Source
161
7.52k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKS7_
Line
Count
Source
161
152k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKS7_
Line
Count
Source
161
335
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKS9_
Line
Count
Source
161
122k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKS9_
Line
Count
Source
161
268
{}
162
163
template <typename Builder, typename T>
164
bigfield<Builder, T>::bigfield(bigfield&& other)
165
    : context(other.context)
166
    , binary_basis_limbs{ other.binary_basis_limbs[0],
167
                          other.binary_basis_limbs[1],
168
                          other.binary_basis_limbs[2],
169
                          other.binary_basis_limbs[3] }
170
    , prime_basis_limb(other.prime_basis_limb)
171
1.09M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EOS6_
Line
Count
Source
171
1.00M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EOS6_
Line
Count
Source
171
788
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EOS8_
Line
Count
Source
171
20
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EOS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EOS7_
Line
Count
Source
171
3.56k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EOS7_
Line
Count
Source
171
123
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EOS9_
Line
Count
Source
171
61.5k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EOS9_
Line
Count
Source
171
2.05k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EOS7_
Line
Count
Source
171
11.3k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EOS7_
Line
Count
Source
171
50
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EOS9_
Line
Count
Source
171
9.06k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EOS9_
Line
Count
Source
171
40
{}
172
173
/**
174
 * @brief Creates a bigfield element from a uint512_t.
175
 * Bigfield element is constructed as a witness and not a circuit constant
176
 *
177
 * @param ctx
178
 * @param value
179
 * @param can_overflow Can the input value have more than log2(modulus) bits?
180
 * @param maximum_bitlength Provide the explicit maximum bitlength if known. Otherwise bigfield max value will be
181
 * either log2(modulus) bits iff can_overflow = false, or (4 * NUM_LIMB_BITS) iff can_overflow = true
182
 * @return bigfield<Builder, T>
183
 *
184
 * @details This method is 1 gate more efficient than constructing from 2 field_ct elements.
185
 */
186
template <typename Builder, typename T>
187
bigfield<Builder, T> bigfield<Builder, T>::create_from_u512_as_witness(Builder* ctx,
188
                                                                       const uint512_t& value,
189
                                                                       const bool can_overflow,
190
                                                                       const size_t maximum_bitlength)
191
2.13M
{
192
2.13M
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
2.13M
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
0
    std::array<uint256_t, 4> limbs;
195
0
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
0
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
0
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
0
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
2.13M
    if constexpr (HasPlookup<Builder>) {
201
2.13M
        field_t<Builder> limb_0(ctx);
202
2.13M
        field_t<Builder> limb_1(ctx);
203
2.13M
        field_t<Builder> limb_2(ctx);
204
2.13M
        field_t<Builder> limb_3(ctx);
205
2.13M
        field_t<Builder> prime_limb(ctx);
206
2.13M
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
2.13M
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
2.13M
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
2.13M
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
2.13M
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
2.13M
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
2.13M
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
2.13M
                                   limb_2.get_normalized_witness_index(),
215
2.13M
                                   limb_3.get_normalized_witness_index(),
216
2.13M
                                   prime_limb.get_normalized_witness_index(),
217
2.13M
                                   shift_1,
218
2.13M
                                   shift_2,
219
2.13M
                                   shift_3,
220
2.13M
                                   -1,
221
2.13M
                                   0 },
222
2.13M
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
2.13M
        ctx->create_dummy_gate(
226
2.13M
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
2.13M
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
2.13M
        bigfield result(ctx);
231
2.13M
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
2.13M
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
2.13M
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
2.13M
        result.binary_basis_limbs[3] =
235
2.13M
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
2.13M
        if (maximum_bitlength > 0) {
239
1.06M
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
0
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
0
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
0
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
0
        }
244
0
        result.prime_basis_limb = prime_limb;
245
0
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
0
                                       limb_1.get_normalized_witness_index(),
247
0
                                       (size_t)NUM_LIMB_BITS,
248
0
                                       (size_t)NUM_LIMB_BITS);
249
0
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
0
                                       limb_3.get_normalized_witness_index(),
251
0
                                       (size_t)NUM_LIMB_BITS,
252
0
                                       (size_t)num_last_limb_bits);
253
254
0
        return result;
255
2.13M
    } else {
256
0
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
0
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
0
                        can_overflow,
259
0
                        maximum_bitlength);
260
0
    }
261
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Line
Count
Source
191
1.97M
{
192
1.97M
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
1.97M
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
1.97M
    std::array<uint256_t, 4> limbs;
195
1.97M
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
1.97M
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
1.97M
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
1.97M
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
1.97M
    if constexpr (HasPlookup<Builder>) {
201
1.97M
        field_t<Builder> limb_0(ctx);
202
1.97M
        field_t<Builder> limb_1(ctx);
203
1.97M
        field_t<Builder> limb_2(ctx);
204
1.97M
        field_t<Builder> limb_3(ctx);
205
1.97M
        field_t<Builder> prime_limb(ctx);
206
1.97M
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
1.97M
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
1.97M
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
1.97M
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
1.97M
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
1.97M
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
1.97M
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
1.97M
                                   limb_2.get_normalized_witness_index(),
215
1.97M
                                   limb_3.get_normalized_witness_index(),
216
1.97M
                                   prime_limb.get_normalized_witness_index(),
217
1.97M
                                   shift_1,
218
1.97M
                                   shift_2,
219
1.97M
                                   shift_3,
220
1.97M
                                   -1,
221
1.97M
                                   0 },
222
1.97M
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
1.97M
        ctx->create_dummy_gate(
226
1.97M
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
1.97M
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
1.97M
        bigfield result(ctx);
231
1.97M
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
1.97M
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
1.97M
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
1.97M
        result.binary_basis_limbs[3] =
235
1.97M
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
1.97M
        if (maximum_bitlength > 0) {
239
986k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
986k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
986k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
986k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
986k
        }
244
1.97M
        result.prime_basis_limb = prime_limb;
245
1.97M
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
1.97M
                                       limb_1.get_normalized_witness_index(),
247
1.97M
                                       (size_t)NUM_LIMB_BITS,
248
1.97M
                                       (size_t)NUM_LIMB_BITS);
249
1.97M
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
1.97M
                                       limb_3.get_normalized_witness_index(),
251
1.97M
                                       (size_t)NUM_LIMB_BITS,
252
1.97M
                                       (size_t)num_last_limb_bits);
253
254
1.97M
        return result;
255
1.97M
    } else {
256
1.97M
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
1.97M
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
1.97M
                        can_overflow,
259
1.97M
                        maximum_bitlength);
260
1.97M
    }
261
1.97M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Line
Count
Source
191
76
{
192
76
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
76
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
76
    std::array<uint256_t, 4> limbs;
195
76
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
76
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
76
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
76
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
76
    if constexpr (HasPlookup<Builder>) {
201
76
        field_t<Builder> limb_0(ctx);
202
76
        field_t<Builder> limb_1(ctx);
203
76
        field_t<Builder> limb_2(ctx);
204
76
        field_t<Builder> limb_3(ctx);
205
76
        field_t<Builder> prime_limb(ctx);
206
76
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
76
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
76
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
76
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
76
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
76
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
76
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
76
                                   limb_2.get_normalized_witness_index(),
215
76
                                   limb_3.get_normalized_witness_index(),
216
76
                                   prime_limb.get_normalized_witness_index(),
217
76
                                   shift_1,
218
76
                                   shift_2,
219
76
                                   shift_3,
220
76
                                   -1,
221
76
                                   0 },
222
76
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
76
        ctx->create_dummy_gate(
226
76
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
76
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
76
        bigfield result(ctx);
231
76
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
76
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
76
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
76
        result.binary_basis_limbs[3] =
235
76
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
76
        if (maximum_bitlength > 0) {
239
38
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
38
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
38
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
38
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
38
        }
244
76
        result.prime_basis_limb = prime_limb;
245
76
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
76
                                       limb_1.get_normalized_witness_index(),
247
76
                                       (size_t)NUM_LIMB_BITS,
248
76
                                       (size_t)NUM_LIMB_BITS);
249
76
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
76
                                       limb_3.get_normalized_witness_index(),
251
76
                                       (size_t)NUM_LIMB_BITS,
252
76
                                       (size_t)num_last_limb_bits);
253
254
76
        return result;
255
76
    } else {
256
76
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
76
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
76
                        can_overflow,
259
76
                        maximum_bitlength);
260
76
    }
261
76
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSA_9uint256_tEEEbm
Line
Count
Source
191
32
{
192
32
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
32
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
32
    std::array<uint256_t, 4> limbs;
195
32
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
32
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
32
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
32
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
32
    if constexpr (HasPlookup<Builder>) {
201
32
        field_t<Builder> limb_0(ctx);
202
32
        field_t<Builder> limb_1(ctx);
203
32
        field_t<Builder> limb_2(ctx);
204
32
        field_t<Builder> limb_3(ctx);
205
32
        field_t<Builder> prime_limb(ctx);
206
32
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
32
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
32
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
32
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
32
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
32
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
32
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
32
                                   limb_2.get_normalized_witness_index(),
215
32
                                   limb_3.get_normalized_witness_index(),
216
32
                                   prime_limb.get_normalized_witness_index(),
217
32
                                   shift_1,
218
32
                                   shift_2,
219
32
                                   shift_3,
220
32
                                   -1,
221
32
                                   0 },
222
32
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
32
        ctx->create_dummy_gate(
226
32
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
32
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
32
        bigfield result(ctx);
231
32
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
32
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
32
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
32
        result.binary_basis_limbs[3] =
235
32
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
32
        if (maximum_bitlength > 0) {
239
16
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
16
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
16
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
16
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
16
        }
244
32
        result.prime_basis_limb = prime_limb;
245
32
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
32
                                       limb_1.get_normalized_witness_index(),
247
32
                                       (size_t)NUM_LIMB_BITS,
248
32
                                       (size_t)NUM_LIMB_BITS);
249
32
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
32
                                       limb_3.get_normalized_witness_index(),
251
32
                                       (size_t)NUM_LIMB_BITS,
252
32
                                       (size_t)num_last_limb_bits);
253
254
32
        return result;
255
32
    } else {
256
32
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
32
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
32
                        can_overflow,
259
32
                        maximum_bitlength);
260
32
    }
261
32
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
8.01k
{
192
8.01k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
8.01k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
8.01k
    std::array<uint256_t, 4> limbs;
195
8.01k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
8.01k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
8.01k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
8.01k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
8.01k
    if constexpr (HasPlookup<Builder>) {
201
8.01k
        field_t<Builder> limb_0(ctx);
202
8.01k
        field_t<Builder> limb_1(ctx);
203
8.01k
        field_t<Builder> limb_2(ctx);
204
8.01k
        field_t<Builder> limb_3(ctx);
205
8.01k
        field_t<Builder> prime_limb(ctx);
206
8.01k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
8.01k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
8.01k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
8.01k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
8.01k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
8.01k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
8.01k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
8.01k
                                   limb_2.get_normalized_witness_index(),
215
8.01k
                                   limb_3.get_normalized_witness_index(),
216
8.01k
                                   prime_limb.get_normalized_witness_index(),
217
8.01k
                                   shift_1,
218
8.01k
                                   shift_2,
219
8.01k
                                   shift_3,
220
8.01k
                                   -1,
221
8.01k
                                   0 },
222
8.01k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
8.01k
        ctx->create_dummy_gate(
226
8.01k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
8.01k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
8.01k
        bigfield result(ctx);
231
8.01k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
8.01k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
8.01k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
8.01k
        result.binary_basis_limbs[3] =
235
8.01k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
8.01k
        if (maximum_bitlength > 0) {
239
4.01k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
4.01k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
4.01k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
4.01k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
4.01k
        }
244
8.01k
        result.prime_basis_limb = prime_limb;
245
8.01k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
8.01k
                                       limb_1.get_normalized_witness_index(),
247
8.01k
                                       (size_t)NUM_LIMB_BITS,
248
8.01k
                                       (size_t)NUM_LIMB_BITS);
249
8.01k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
8.01k
                                       limb_3.get_normalized_witness_index(),
251
8.01k
                                       (size_t)NUM_LIMB_BITS,
252
8.01k
                                       (size_t)num_last_limb_bits);
253
254
8.01k
        return result;
255
8.01k
    } else {
256
8.01k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
8.01k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
8.01k
                        can_overflow,
259
8.01k
                        maximum_bitlength);
260
8.01k
    }
261
8.01k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
54
{
192
54
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
54
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
54
    std::array<uint256_t, 4> limbs;
195
54
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
54
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
54
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
54
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
54
    if constexpr (HasPlookup<Builder>) {
201
54
        field_t<Builder> limb_0(ctx);
202
54
        field_t<Builder> limb_1(ctx);
203
54
        field_t<Builder> limb_2(ctx);
204
54
        field_t<Builder> limb_3(ctx);
205
54
        field_t<Builder> prime_limb(ctx);
206
54
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
54
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
54
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
54
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
54
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
54
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
54
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
54
                                   limb_2.get_normalized_witness_index(),
215
54
                                   limb_3.get_normalized_witness_index(),
216
54
                                   prime_limb.get_normalized_witness_index(),
217
54
                                   shift_1,
218
54
                                   shift_2,
219
54
                                   shift_3,
220
54
                                   -1,
221
54
                                   0 },
222
54
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
54
        ctx->create_dummy_gate(
226
54
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
54
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
54
        bigfield result(ctx);
231
54
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
54
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
54
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
54
        result.binary_basis_limbs[3] =
235
54
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
54
        if (maximum_bitlength > 0) {
239
27
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
27
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
27
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
27
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
27
        }
244
54
        result.prime_basis_limb = prime_limb;
245
54
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
54
                                       limb_1.get_normalized_witness_index(),
247
54
                                       (size_t)NUM_LIMB_BITS,
248
54
                                       (size_t)NUM_LIMB_BITS);
249
54
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
54
                                       limb_3.get_normalized_witness_index(),
251
54
                                       (size_t)NUM_LIMB_BITS,
252
54
                                       (size_t)num_last_limb_bits);
253
254
54
        return result;
255
54
    } else {
256
54
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
54
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
54
                        can_overflow,
259
54
                        maximum_bitlength);
260
54
    }
261
54
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Line
Count
Source
191
136k
{
192
136k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
136k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
136k
    std::array<uint256_t, 4> limbs;
195
136k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
136k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
136k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
136k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
136k
    if constexpr (HasPlookup<Builder>) {
201
136k
        field_t<Builder> limb_0(ctx);
202
136k
        field_t<Builder> limb_1(ctx);
203
136k
        field_t<Builder> limb_2(ctx);
204
136k
        field_t<Builder> limb_3(ctx);
205
136k
        field_t<Builder> prime_limb(ctx);
206
136k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
136k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
136k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
136k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
136k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
136k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
136k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
136k
                                   limb_2.get_normalized_witness_index(),
215
136k
                                   limb_3.get_normalized_witness_index(),
216
136k
                                   prime_limb.get_normalized_witness_index(),
217
136k
                                   shift_1,
218
136k
                                   shift_2,
219
136k
                                   shift_3,
220
136k
                                   -1,
221
136k
                                   0 },
222
136k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
136k
        ctx->create_dummy_gate(
226
136k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
136k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
136k
        bigfield result(ctx);
231
136k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
136k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
136k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
136k
        result.binary_basis_limbs[3] =
235
136k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
136k
        if (maximum_bitlength > 0) {
239
68.4k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
68.4k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
68.4k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
68.4k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
68.4k
        }
244
136k
        result.prime_basis_limb = prime_limb;
245
136k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
136k
                                       limb_1.get_normalized_witness_index(),
247
136k
                                       (size_t)NUM_LIMB_BITS,
248
136k
                                       (size_t)NUM_LIMB_BITS);
249
136k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
136k
                                       limb_3.get_normalized_witness_index(),
251
136k
                                       (size_t)NUM_LIMB_BITS,
252
136k
                                       (size_t)num_last_limb_bits);
253
254
136k
        return result;
255
136k
    } else {
256
136k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
136k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
136k
                        can_overflow,
259
136k
                        maximum_bitlength);
260
136k
    }
261
136k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Line
Count
Source
191
912
{
192
912
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
912
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
912
    std::array<uint256_t, 4> limbs;
195
912
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
912
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
912
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
912
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
912
    if constexpr (HasPlookup<Builder>) {
201
912
        field_t<Builder> limb_0(ctx);
202
912
        field_t<Builder> limb_1(ctx);
203
912
        field_t<Builder> limb_2(ctx);
204
912
        field_t<Builder> limb_3(ctx);
205
912
        field_t<Builder> prime_limb(ctx);
206
912
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
912
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
912
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
912
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
912
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
912
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
912
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
912
                                   limb_2.get_normalized_witness_index(),
215
912
                                   limb_3.get_normalized_witness_index(),
216
912
                                   prime_limb.get_normalized_witness_index(),
217
912
                                   shift_1,
218
912
                                   shift_2,
219
912
                                   shift_3,
220
912
                                   -1,
221
912
                                   0 },
222
912
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
912
        ctx->create_dummy_gate(
226
912
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
912
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
912
        bigfield result(ctx);
231
912
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
912
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
912
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
912
        result.binary_basis_limbs[3] =
235
912
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
912
        if (maximum_bitlength > 0) {
239
456
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
456
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
456
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
456
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
456
        }
244
912
        result.prime_basis_limb = prime_limb;
245
912
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
912
                                       limb_1.get_normalized_witness_index(),
247
912
                                       (size_t)NUM_LIMB_BITS,
248
912
                                       (size_t)NUM_LIMB_BITS);
249
912
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
912
                                       limb_3.get_normalized_witness_index(),
251
912
                                       (size_t)NUM_LIMB_BITS,
252
912
                                       (size_t)num_last_limb_bits);
253
254
912
        return result;
255
912
    } else {
256
912
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
912
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
912
                        can_overflow,
259
912
                        maximum_bitlength);
260
912
    }
261
912
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
11.1k
{
192
11.1k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
11.1k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
11.1k
    std::array<uint256_t, 4> limbs;
195
11.1k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
11.1k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
11.1k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
11.1k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
11.1k
    if constexpr (HasPlookup<Builder>) {
201
11.1k
        field_t<Builder> limb_0(ctx);
202
11.1k
        field_t<Builder> limb_1(ctx);
203
11.1k
        field_t<Builder> limb_2(ctx);
204
11.1k
        field_t<Builder> limb_3(ctx);
205
11.1k
        field_t<Builder> prime_limb(ctx);
206
11.1k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
11.1k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
11.1k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
11.1k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
11.1k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
11.1k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
11.1k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
11.1k
                                   limb_2.get_normalized_witness_index(),
215
11.1k
                                   limb_3.get_normalized_witness_index(),
216
11.1k
                                   prime_limb.get_normalized_witness_index(),
217
11.1k
                                   shift_1,
218
11.1k
                                   shift_2,
219
11.1k
                                   shift_3,
220
11.1k
                                   -1,
221
11.1k
                                   0 },
222
11.1k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
11.1k
        ctx->create_dummy_gate(
226
11.1k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
11.1k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
11.1k
        bigfield result(ctx);
231
11.1k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
11.1k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
11.1k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
11.1k
        result.binary_basis_limbs[3] =
235
11.1k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
11.1k
        if (maximum_bitlength > 0) {
239
5.56k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
5.56k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
5.56k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
5.56k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
5.56k
        }
244
11.1k
        result.prime_basis_limb = prime_limb;
245
11.1k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
11.1k
                                       limb_1.get_normalized_witness_index(),
247
11.1k
                                       (size_t)NUM_LIMB_BITS,
248
11.1k
                                       (size_t)NUM_LIMB_BITS);
249
11.1k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
11.1k
                                       limb_3.get_normalized_witness_index(),
251
11.1k
                                       (size_t)NUM_LIMB_BITS,
252
11.1k
                                       (size_t)num_last_limb_bits);
253
254
11.1k
        return result;
255
11.1k
    } else {
256
11.1k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
11.1k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
11.1k
                        can_overflow,
259
11.1k
                        maximum_bitlength);
260
11.1k
    }
261
11.1k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
20
{
192
20
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
20
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
20
    std::array<uint256_t, 4> limbs;
195
20
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
20
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
20
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
20
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
20
    if constexpr (HasPlookup<Builder>) {
201
20
        field_t<Builder> limb_0(ctx);
202
20
        field_t<Builder> limb_1(ctx);
203
20
        field_t<Builder> limb_2(ctx);
204
20
        field_t<Builder> limb_3(ctx);
205
20
        field_t<Builder> prime_limb(ctx);
206
20
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
20
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
20
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
20
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
20
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
20
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
20
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
20
                                   limb_2.get_normalized_witness_index(),
215
20
                                   limb_3.get_normalized_witness_index(),
216
20
                                   prime_limb.get_normalized_witness_index(),
217
20
                                   shift_1,
218
20
                                   shift_2,
219
20
                                   shift_3,
220
20
                                   -1,
221
20
                                   0 },
222
20
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
20
        ctx->create_dummy_gate(
226
20
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
20
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
20
        bigfield result(ctx);
231
20
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
20
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
20
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
20
        result.binary_basis_limbs[3] =
235
20
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
20
        if (maximum_bitlength > 0) {
239
10
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
10
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
10
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
10
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
10
        }
244
20
        result.prime_basis_limb = prime_limb;
245
20
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
20
                                       limb_1.get_normalized_witness_index(),
247
20
                                       (size_t)NUM_LIMB_BITS,
248
20
                                       (size_t)NUM_LIMB_BITS);
249
20
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
20
                                       limb_3.get_normalized_witness_index(),
251
20
                                       (size_t)NUM_LIMB_BITS,
252
20
                                       (size_t)num_last_limb_bits);
253
254
20
        return result;
255
20
    } else {
256
20
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
20
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
20
                        can_overflow,
259
20
                        maximum_bitlength);
260
20
    }
261
20
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Line
Count
Source
191
8.90k
{
192
8.90k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
8.90k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
8.90k
    std::array<uint256_t, 4> limbs;
195
8.90k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
8.90k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
8.90k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
8.90k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
8.90k
    if constexpr (HasPlookup<Builder>) {
201
8.90k
        field_t<Builder> limb_0(ctx);
202
8.90k
        field_t<Builder> limb_1(ctx);
203
8.90k
        field_t<Builder> limb_2(ctx);
204
8.90k
        field_t<Builder> limb_3(ctx);
205
8.90k
        field_t<Builder> prime_limb(ctx);
206
8.90k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
8.90k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
8.90k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
8.90k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
8.90k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
8.90k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
8.90k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
8.90k
                                   limb_2.get_normalized_witness_index(),
215
8.90k
                                   limb_3.get_normalized_witness_index(),
216
8.90k
                                   prime_limb.get_normalized_witness_index(),
217
8.90k
                                   shift_1,
218
8.90k
                                   shift_2,
219
8.90k
                                   shift_3,
220
8.90k
                                   -1,
221
8.90k
                                   0 },
222
8.90k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
8.90k
        ctx->create_dummy_gate(
226
8.90k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
8.90k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
8.90k
        bigfield result(ctx);
231
8.90k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
8.90k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
8.90k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
8.90k
        result.binary_basis_limbs[3] =
235
8.90k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
8.90k
        if (maximum_bitlength > 0) {
239
4.45k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
4.45k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
4.45k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
4.45k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
4.45k
        }
244
8.90k
        result.prime_basis_limb = prime_limb;
245
8.90k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
8.90k
                                       limb_1.get_normalized_witness_index(),
247
8.90k
                                       (size_t)NUM_LIMB_BITS,
248
8.90k
                                       (size_t)NUM_LIMB_BITS);
249
8.90k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
8.90k
                                       limb_3.get_normalized_witness_index(),
251
8.90k
                                       (size_t)NUM_LIMB_BITS,
252
8.90k
                                       (size_t)num_last_limb_bits);
253
254
8.90k
        return result;
255
8.90k
    } else {
256
8.90k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
8.90k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
8.90k
                        can_overflow,
259
8.90k
                        maximum_bitlength);
260
8.90k
    }
261
8.90k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Line
Count
Source
191
16
{
192
16
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
16
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
16
    std::array<uint256_t, 4> limbs;
195
16
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
16
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
16
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
16
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
16
    if constexpr (HasPlookup<Builder>) {
201
16
        field_t<Builder> limb_0(ctx);
202
16
        field_t<Builder> limb_1(ctx);
203
16
        field_t<Builder> limb_2(ctx);
204
16
        field_t<Builder> limb_3(ctx);
205
16
        field_t<Builder> prime_limb(ctx);
206
16
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
16
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
16
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
16
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
16
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
16
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
16
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
16
                                   limb_2.get_normalized_witness_index(),
215
16
                                   limb_3.get_normalized_witness_index(),
216
16
                                   prime_limb.get_normalized_witness_index(),
217
16
                                   shift_1,
218
16
                                   shift_2,
219
16
                                   shift_3,
220
16
                                   -1,
221
16
                                   0 },
222
16
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
16
        ctx->create_dummy_gate(
226
16
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
16
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
16
        bigfield result(ctx);
231
16
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
16
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
16
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
16
        result.binary_basis_limbs[3] =
235
16
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
16
        if (maximum_bitlength > 0) {
239
8
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
8
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
8
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
8
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
8
        }
244
16
        result.prime_basis_limb = prime_limb;
245
16
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
16
                                       limb_1.get_normalized_witness_index(),
247
16
                                       (size_t)NUM_LIMB_BITS,
248
16
                                       (size_t)NUM_LIMB_BITS);
249
16
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
16
                                       limb_3.get_normalized_witness_index(),
251
16
                                       (size_t)NUM_LIMB_BITS,
252
16
                                       (size_t)num_last_limb_bits);
253
254
16
        return result;
255
16
    } else {
256
16
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
16
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
16
                        can_overflow,
259
16
                        maximum_bitlength);
260
16
    }
261
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSA_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
262
263
template <typename Builder, typename T> bigfield<Builder, T>::bigfield(const byte_array<Builder>& bytes)
264
450
{
265
450
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
900
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
900
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
900
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
900
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
900
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
900
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
900
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
900
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
900
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
900
        sum.assert_equal(split_byte);
278
900
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
900
                                                                  (field_t<Builder>)hi_nibble);
280
900
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESB_SF_
Line
Count
Source
266
62
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
62
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
62
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
62
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
62
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
62
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
62
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
62
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
62
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
62
        sum.assert_equal(split_byte);
278
62
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
62
                                                                  (field_t<Builder>)hi_nibble);
280
62
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESB_SF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESD_SH_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESC_SG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
20
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
20
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
20
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
20
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
20
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
20
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
20
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
20
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
20
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
20
        sum.assert_equal(split_byte);
278
20
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
20
                                                                  (field_t<Builder>)hi_nibble);
280
20
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
48
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
48
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
48
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
48
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
48
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
48
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
48
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
48
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
48
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
48
        sum.assert_equal(split_byte);
278
48
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
48
                                                                  (field_t<Builder>)hi_nibble);
280
48
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
Line
Count
Source
266
684
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
684
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
684
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
684
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
684
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
684
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
684
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
684
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
684
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
684
        sum.assert_equal(split_byte);
278
684
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
684
                                                                  (field_t<Builder>)hi_nibble);
280
684
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
16
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
16
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
16
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
16
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
16
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
16
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
16
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
16
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
16
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
16
        sum.assert_equal(split_byte);
278
16
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
16
                                                                  (field_t<Builder>)hi_nibble);
280
16
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
30
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
30
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
30
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
30
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
30
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
30
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
30
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
30
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
30
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
30
        sum.assert_equal(split_byte);
278
30
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
30
                                                                  (field_t<Builder>)hi_nibble);
280
30
    };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
Line
Count
Source
266
16
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
16
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
16
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
16
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
16
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
16
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
16
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
16
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
16
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
16
        sum.assert_equal(split_byte);
278
16
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
16
                                                                  (field_t<Builder>)hi_nibble);
280
16
    };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
Line
Count
Source
266
24
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
24
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
24
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
24
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
24
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
24
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
24
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
24
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
24
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
24
        sum.assert_equal(split_byte);
278
24
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
24
                                                                  (field_t<Builder>)hi_nibble);
280
24
    };
281
282
0
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
0
                                                                  const field_t<Builder>& hi_bytes,
284
0
                                                                  const field_t<Builder>& lo_bytes,
285
900
                                                                  const field_t<Builder>& split_byte) {
286
900
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
900
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
900
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
900
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
900
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESF_SF_E_clESB_SF_SF_SF_
Line
Count
Source
285
62
                                                                  const field_t<Builder>& split_byte) {
286
62
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
62
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
62
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
62
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
62
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESF_SF_E_clESB_SF_SF_SF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESH_SH_E_clESD_SH_SH_SH_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESG_SG_E_clESC_SG_SG_SG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
20
                                                                  const field_t<Builder>& split_byte) {
286
20
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
20
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
20
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
20
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
20
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
48
                                                                  const field_t<Builder>& split_byte) {
286
48
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
48
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
48
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
48
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
48
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
Line
Count
Source
285
684
                                                                  const field_t<Builder>& split_byte) {
286
684
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
684
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
684
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
684
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
684
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
16
                                                                  const field_t<Builder>& split_byte) {
286
16
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
16
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
16
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
16
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
16
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
30
                                                                  const field_t<Builder>& split_byte) {
286
30
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
30
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
30
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
30
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
30
    };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
Line
Count
Source
285
16
                                                                  const field_t<Builder>& split_byte) {
286
16
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
16
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
16
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
16
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
16
    };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
Line
Count
Source
285
24
                                                                  const field_t<Builder>& split_byte) {
286
24
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
24
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
24
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
24
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
24
    };
292
0
    Builder* ctx = bytes.get_context();
293
294
0
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
0
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
0
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
0
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
0
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
0
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
0
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
0
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
0
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
0
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
0
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
0
    *this = res;
310
0
    set_origin_tag(bytes.get_origin_tag());
311
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
31
{
265
31
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
31
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
31
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
31
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
31
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
31
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
31
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
31
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
31
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
31
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
31
        sum.assert_equal(split_byte);
278
31
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
31
                                                                  (field_t<Builder>)hi_nibble);
280
31
    };
281
282
31
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
31
                                                                  const field_t<Builder>& hi_bytes,
284
31
                                                                  const field_t<Builder>& lo_bytes,
285
31
                                                                  const field_t<Builder>& split_byte) {
286
31
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
31
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
31
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
31
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
31
    };
292
31
    Builder* ctx = bytes.get_context();
293
294
31
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
31
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
31
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
31
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
31
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
31
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
31
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
31
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
31
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
31
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
31
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
31
    *this = res;
310
31
    set_origin_tag(bytes.get_origin_tag());
311
31
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_10byte_arrayIS6_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
10
{
265
10
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
10
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
10
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
10
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
10
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
10
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
10
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
10
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
10
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
10
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
10
        sum.assert_equal(split_byte);
278
10
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
10
                                                                  (field_t<Builder>)hi_nibble);
280
10
    };
281
282
10
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
10
                                                                  const field_t<Builder>& hi_bytes,
284
10
                                                                  const field_t<Builder>& lo_bytes,
285
10
                                                                  const field_t<Builder>& split_byte) {
286
10
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
10
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
10
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
10
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
10
    };
292
10
    Builder* ctx = bytes.get_context();
293
294
10
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
10
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
10
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
10
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
10
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
10
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
10
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
10
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
10
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
10
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
10
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
10
    *this = res;
310
10
    set_origin_tag(bytes.get_origin_tag());
311
10
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
24
{
265
24
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
24
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
24
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
24
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
24
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
24
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
24
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
24
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
24
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
24
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
24
        sum.assert_equal(split_byte);
278
24
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
24
                                                                  (field_t<Builder>)hi_nibble);
280
24
    };
281
282
24
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
24
                                                                  const field_t<Builder>& hi_bytes,
284
24
                                                                  const field_t<Builder>& lo_bytes,
285
24
                                                                  const field_t<Builder>& split_byte) {
286
24
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
24
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
24
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
24
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
24
    };
292
24
    Builder* ctx = bytes.get_context();
293
294
24
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
24
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
24
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
24
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
24
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
24
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
24
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
24
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
24
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
24
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
24
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
24
    *this = res;
310
24
    set_origin_tag(bytes.get_origin_tag());
311
24
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKNS0_10byte_arrayIS6_EE
Line
Count
Source
264
342
{
265
342
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
342
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
342
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
342
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
342
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
342
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
342
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
342
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
342
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
342
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
342
        sum.assert_equal(split_byte);
278
342
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
342
                                                                  (field_t<Builder>)hi_nibble);
280
342
    };
281
282
342
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
342
                                                                  const field_t<Builder>& hi_bytes,
284
342
                                                                  const field_t<Builder>& lo_bytes,
285
342
                                                                  const field_t<Builder>& split_byte) {
286
342
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
342
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
342
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
342
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
342
    };
292
342
    Builder* ctx = bytes.get_context();
293
294
342
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
342
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
342
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
342
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
342
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
342
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
342
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
342
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
342
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
342
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
342
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
342
    *this = res;
310
342
    set_origin_tag(bytes.get_origin_tag());
311
342
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
8
{
265
8
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
8
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
8
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
8
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
8
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
8
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
8
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
8
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
8
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
8
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
8
        sum.assert_equal(split_byte);
278
8
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
8
                                                                  (field_t<Builder>)hi_nibble);
280
8
    };
281
282
8
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
8
                                                                  const field_t<Builder>& hi_bytes,
284
8
                                                                  const field_t<Builder>& lo_bytes,
285
8
                                                                  const field_t<Builder>& split_byte) {
286
8
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
8
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
8
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
8
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
8
    };
292
8
    Builder* ctx = bytes.get_context();
293
294
8
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
8
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
8
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
8
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
8
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
8
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
8
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
8
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
8
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
8
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
8
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
8
    *this = res;
310
8
    set_origin_tag(bytes.get_origin_tag());
311
8
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
15
{
265
15
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
15
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
15
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
15
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
15
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
15
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
15
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
15
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
15
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
15
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
15
        sum.assert_equal(split_byte);
278
15
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
15
                                                                  (field_t<Builder>)hi_nibble);
280
15
    };
281
282
15
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
15
                                                                  const field_t<Builder>& hi_bytes,
284
15
                                                                  const field_t<Builder>& lo_bytes,
285
15
                                                                  const field_t<Builder>& split_byte) {
286
15
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
15
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
15
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
15
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
15
    };
292
15
    Builder* ctx = bytes.get_context();
293
294
15
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
15
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
15
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
15
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
15
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
15
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
15
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
15
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
15
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
15
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
15
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
15
    *this = res;
310
15
    set_origin_tag(bytes.get_origin_tag());
311
15
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
Line
Count
Source
264
8
{
265
8
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
8
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
8
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
8
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
8
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
8
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
8
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
8
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
8
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
8
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
8
        sum.assert_equal(split_byte);
278
8
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
8
                                                                  (field_t<Builder>)hi_nibble);
280
8
    };
281
282
8
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
8
                                                                  const field_t<Builder>& hi_bytes,
284
8
                                                                  const field_t<Builder>& lo_bytes,
285
8
                                                                  const field_t<Builder>& split_byte) {
286
8
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
8
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
8
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
8
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
8
    };
292
8
    Builder* ctx = bytes.get_context();
293
294
8
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
8
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
8
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
8
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
8
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
8
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
8
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
8
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
8
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
8
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
8
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
8
    *this = res;
310
8
    set_origin_tag(bytes.get_origin_tag());
311
8
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKNS0_10byte_arrayIS6_EE
Line
Count
Source
264
12
{
265
12
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
12
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
12
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
12
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
12
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
12
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
12
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
12
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
12
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
12
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
12
        sum.assert_equal(split_byte);
278
12
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
12
                                                                  (field_t<Builder>)hi_nibble);
280
12
    };
281
282
12
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
12
                                                                  const field_t<Builder>& hi_bytes,
284
12
                                                                  const field_t<Builder>& lo_bytes,
285
12
                                                                  const field_t<Builder>& split_byte) {
286
12
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
12
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
12
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
12
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
12
    };
292
12
    Builder* ctx = bytes.get_context();
293
294
12
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
12
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
12
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
12
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
12
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
12
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
12
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
12
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
12
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
12
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
12
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
12
    *this = res;
310
12
    set_origin_tag(bytes.get_origin_tag());
311
12
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_10byte_arrayIS6_EE
312
313
template <typename Builder, typename T> bigfield<Builder, T>& bigfield<Builder, T>::operator=(const bigfield& other)
314
1.59M
{
315
1.59M
    context = other.context;
316
1.59M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
1.59M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
1.59M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
1.59M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
1.59M
    prime_basis_limb = other.prime_basis_limb;
321
1.59M
    return *this;
322
1.59M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEaSERKS6_
Line
Count
Source
314
1.52M
{
315
1.52M
    context = other.context;
316
1.52M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
1.52M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
1.52M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
1.52M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
1.52M
    prime_basis_limb = other.prime_basis_limb;
321
1.52M
    return *this;
322
1.52M
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEaSERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEaSERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EaSERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEaSERKS7_
Line
Count
Source
314
3.64k
{
315
3.64k
    context = other.context;
316
3.64k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
3.64k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
3.64k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
3.64k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
3.64k
    prime_basis_limb = other.prime_basis_limb;
321
3.64k
    return *this;
322
3.64k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEaSERKS7_
Line
Count
Source
314
60
{
315
60
    context = other.context;
316
60
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
60
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
60
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
60
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
60
    prime_basis_limb = other.prime_basis_limb;
321
60
    return *this;
322
60
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEaSERKS9_
Line
Count
Source
314
64.0k
{
315
64.0k
    context = other.context;
316
64.0k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
64.0k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
64.0k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
64.0k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
64.0k
    prime_basis_limb = other.prime_basis_limb;
321
64.0k
    return *this;
322
64.0k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEaSERKS9_
Line
Count
Source
314
798
{
315
798
    context = other.context;
316
798
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
798
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
798
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
798
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
798
    prime_basis_limb = other.prime_basis_limb;
321
798
    return *this;
322
798
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEaSERKS7_
Line
Count
Source
314
5.54k
{
315
5.54k
    context = other.context;
316
5.54k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
5.54k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
5.54k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
5.54k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
5.54k
    prime_basis_limb = other.prime_basis_limb;
321
5.54k
    return *this;
322
5.54k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEaSERKS7_
Line
Count
Source
314
15
{
315
15
    context = other.context;
316
15
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
15
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
15
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
15
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
15
    prime_basis_limb = other.prime_basis_limb;
321
15
    return *this;
322
15
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEaSERKS9_
Line
Count
Source
314
4.43k
{
315
4.43k
    context = other.context;
316
4.43k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
4.43k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
4.43k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
4.43k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
4.43k
    prime_basis_limb = other.prime_basis_limb;
321
4.43k
    return *this;
322
4.43k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEaSERKS9_
Line
Count
Source
314
12
{
315
12
    context = other.context;
316
12
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
12
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
12
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
12
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
12
    prime_basis_limb = other.prime_basis_limb;
321
12
    return *this;
322
12
}
323
324
template <typename Builder, typename T> bigfield<Builder, T>& bigfield<Builder, T>::operator=(bigfield&& other)
325
3.73M
{
326
3.73M
    context = other.context;
327
3.73M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
3.73M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
3.73M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
3.73M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
3.73M
    prime_basis_limb = other.prime_basis_limb;
332
3.73M
    return *this;
333
3.73M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEaSEOS6_
Line
Count
Source
325
3.51M
{
326
3.51M
    context = other.context;
327
3.51M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
3.51M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
3.51M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
3.51M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
3.51M
    prime_basis_limb = other.prime_basis_limb;
332
3.51M
    return *this;
333
3.51M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEaSEOS6_
Line
Count
Source
325
1.13k
{
326
1.13k
    context = other.context;
327
1.13k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
1.13k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
1.13k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
1.13k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
1.13k
    prime_basis_limb = other.prime_basis_limb;
332
1.13k
    return *this;
333
1.13k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEaSEOS8_
Line
Count
Source
325
48
{
326
48
    context = other.context;
327
48
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
48
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
48
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
48
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
48
    prime_basis_limb = other.prime_basis_limb;
332
48
    return *this;
333
48
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EaSEOS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEaSEOS7_
Line
Count
Source
325
10.2k
{
326
10.2k
    context = other.context;
327
10.2k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
10.2k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
10.2k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
10.2k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
10.2k
    prime_basis_limb = other.prime_basis_limb;
332
10.2k
    return *this;
333
10.2k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEaSEOS7_
Line
Count
Source
325
126
{
326
126
    context = other.context;
327
126
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
126
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
126
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
126
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
126
    prime_basis_limb = other.prime_basis_limb;
332
126
    return *this;
333
126
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEaSEOS9_
Line
Count
Source
325
178k
{
326
178k
    context = other.context;
327
178k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
178k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
178k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
178k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
178k
    prime_basis_limb = other.prime_basis_limb;
332
178k
    return *this;
333
178k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEaSEOS9_
Line
Count
Source
325
2.05k
{
326
2.05k
    context = other.context;
327
2.05k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
2.05k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
2.05k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
2.05k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
2.05k
    prime_basis_limb = other.prime_basis_limb;
332
2.05k
    return *this;
333
2.05k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEaSEOS7_
Line
Count
Source
325
14.7k
{
326
14.7k
    context = other.context;
327
14.7k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
14.7k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
14.7k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
14.7k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
14.7k
    prime_basis_limb = other.prime_basis_limb;
332
14.7k
    return *this;
333
14.7k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEaSEOS7_
Line
Count
Source
325
70
{
326
70
    context = other.context;
327
70
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
70
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
70
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
70
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
70
    prime_basis_limb = other.prime_basis_limb;
332
70
    return *this;
333
70
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEaSEOS9_
Line
Count
Source
325
11.8k
{
326
11.8k
    context = other.context;
327
11.8k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
11.8k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
11.8k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
11.8k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
11.8k
    prime_basis_limb = other.prime_basis_limb;
332
11.8k
    return *this;
333
11.8k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEaSEOS9_
Line
Count
Source
325
56
{
326
56
    context = other.context;
327
56
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
56
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
56
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
56
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
56
    prime_basis_limb = other.prime_basis_limb;
332
56
    return *this;
333
56
}
334
335
template <typename Builder, typename T> uint512_t bigfield<Builder, T>::get_value() const
336
7.12M
{
337
7.12M
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
7.12M
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
7.12M
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
7.12M
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
7.12M
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
7.12M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9get_valueEv
Line
Count
Source
336
6.54M
{
337
6.54M
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
6.54M
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
6.54M
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
6.54M
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
6.54M
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
6.54M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9get_valueEv
Line
Count
Source
336
847
{
337
847
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
847
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
847
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
847
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
847
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
847
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9get_valueEv
Line
Count
Source
336
67
{
337
67
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
67
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
67
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
67
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
67
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
67
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9get_valueEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9get_valueEv
Line
Count
Source
336
27.1k
{
337
27.1k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
27.1k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
27.1k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
27.1k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
27.1k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
27.1k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9get_valueEv
Line
Count
Source
336
218
{
337
218
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
218
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
218
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
218
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
218
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
218
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9get_valueEv
Line
Count
Source
336
467k
{
337
467k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
467k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
467k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
467k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
467k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
467k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9get_valueEv
Line
Count
Source
336
3.64k
{
337
3.64k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
3.64k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
3.64k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
3.64k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
3.64k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
3.64k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9get_valueEv
Line
Count
Source
336
48.4k
{
337
48.4k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
48.4k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
48.4k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
48.4k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
48.4k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
48.4k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9get_valueEv
Line
Count
Source
336
100
{
337
100
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
100
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
100
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
100
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
100
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
100
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9get_valueEv
Line
Count
Source
336
38.7k
{
337
38.7k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
38.7k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
38.7k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
38.7k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
38.7k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
38.7k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9get_valueEv
Line
Count
Source
336
80
{
337
80
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
80
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
80
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
80
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
80
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
80
}
343
344
template <typename Builder, typename T> uint512_t bigfield<Builder, T>::get_maximum_value() const
345
14.7M
{
346
14.7M
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
14.7M
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
14.7M
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
14.7M
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
14.7M
    return t0 + t1 + t2 + t3;
351
14.7M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
13.5M
{
346
13.5M
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
13.5M
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
13.5M
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
13.5M
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
13.5M
    return t0 + t1 + t2 + t3;
351
13.5M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
1.49k
{
346
1.49k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
1.49k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
1.49k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
1.49k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
1.49k
    return t0 + t1 + t2 + t3;
351
1.49k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
64
{
346
64
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
64
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
64
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
64
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
64
    return t0 + t1 + t2 + t3;
351
64
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17get_maximum_valueEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
55.1k
{
346
55.1k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
55.1k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
55.1k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
55.1k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
55.1k
    return t0 + t1 + t2 + t3;
351
55.1k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
370
{
346
370
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
370
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
370
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
370
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
370
    return t0 + t1 + t2 + t3;
351
370
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
966k
{
346
966k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
966k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
966k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
966k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
966k
    return t0 + t1 + t2 + t3;
351
966k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
5.92k
{
346
5.92k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
5.92k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
5.92k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
5.92k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
5.92k
    return t0 + t1 + t2 + t3;
351
5.92k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
94.9k
{
346
94.9k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
94.9k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
94.9k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
94.9k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
94.9k
    return t0 + t1 + t2 + t3;
351
94.9k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
156
{
346
156
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
156
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
156
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
156
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
156
    return t0 + t1 + t2 + t3;
351
156
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
75.9k
{
346
75.9k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
75.9k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
75.9k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
75.9k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
75.9k
    return t0 + t1 + t2 + t3;
351
75.9k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
128
{
346
128
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
128
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
128
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
128
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
128
    return t0 + t1 + t2 + t3;
351
128
}
352
353
/**
354
 * @brief Add a field element to the lower limb. CAUTION (the element has to be constrained before using this
355
 * function)
356
 *
357
 * @details Sometimes we need to add a small constrained value to a bigfield element (for example, a boolean value),
358
 * but we don't want to construct a full bigfield element for that as it would take too many gates. If the maximum
359
 * value of the field element being added is small enough, we can simply add it to the lowest limb and increase its
360
 * maximum value. That will create 2 additional constraints instead of 5/3 needed to add 2 bigfield elements and
361
 * several needed to construct a bigfield element.
362
 *
363
 * @tparam Builder Builder
364
 * @tparam T Field Parameters
365
 * @param other Field element that will be added to the lower
366
 * @param other_maximum_value The maximum value of other
367
 * @return bigfield<Builder, T> Result
368
 */
369
template <typename Builder, typename T>
370
bigfield<Builder, T> bigfield<Builder, T>::add_to_lower_limb(const field_t<Builder>& other,
371
                                                             uint256_t other_maximum_value) const
372
967
{
373
967
    reduction_check();
374
967
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
967
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
967
    Builder* ctx = context ? context : other.context;
378
379
967
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
967
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
967
    if (is_constant()) {
386
487
        auto context = other.context;
387
1.94k
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
1.46k
            result.binary_basis_limbs[i] =
390
1.46k
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
1.46k
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
1.46k
            result.binary_basis_limbs[i].element.fix_witness();
394
1.46k
            result.context = ctx;
395
1.46k
        }
396
487
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
480
        result = *this;
400
480
    }
401
967
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
967
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
967
    result.prime_basis_limb = prime_basis_limb + other;
405
967
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
967
    return result;
407
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Line
Count
Source
372
7
{
373
7
    reduction_check();
374
7
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
7
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
7
    Builder* ctx = context ? context : other.context;
378
379
7
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
7
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
7
    if (is_constant()) {
386
7
        auto context = other.context;
387
28
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
21
            result.binary_basis_limbs[i] =
390
21
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
21
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
21
            result.binary_basis_limbs[i].element.fix_witness();
394
21
            result.context = ctx;
395
21
        }
396
7
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
0
        result = *this;
400
0
    }
401
7
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
7
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
7
    result.prime_basis_limb = prime_basis_limb + other;
405
7
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
7
    return result;
407
7
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Line
Count
Source
372
48
{
373
48
    reduction_check();
374
48
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
48
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
48
    Builder* ctx = context ? context : other.context;
378
379
48
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
48
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
48
    if (is_constant()) {
386
24
        auto context = other.context;
387
96
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
72
            result.binary_basis_limbs[i] =
390
72
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
72
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
72
            result.binary_basis_limbs[i].element.fix_witness();
394
72
            result.context = ctx;
395
72
        }
396
24
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
24
        result = *this;
400
24
    }
401
48
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
48
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
48
    result.prime_basis_limb = prime_basis_limb + other;
405
48
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
48
    return result;
407
48
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Line
Count
Source
372
912
{
373
912
    reduction_check();
374
912
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
912
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
912
    Builder* ctx = context ? context : other.context;
378
379
912
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
912
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
912
    if (is_constant()) {
386
456
        auto context = other.context;
387
1.82k
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
1.36k
            result.binary_basis_limbs[i] =
390
1.36k
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
1.36k
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
1.36k
            result.binary_basis_limbs[i].element.fix_witness();
394
1.36k
            result.context = ctx;
395
1.36k
        }
396
456
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
456
        result = *this;
400
456
    }
401
912
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
912
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
912
    result.prime_basis_limb = prime_basis_limb + other;
405
912
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
912
    return result;
407
912
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
408
409
template <typename Builder, typename T>
410
bigfield<Builder, T> bigfield<Builder, T>::operator+(const bigfield& other) const
411
158k
{
412
158k
    reduction_check();
413
158k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
158k
    Builder* ctx = context ? context : other.context;
416
417
158k
    if (is_constant() && other.is_constant()) {
418
1.50k
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
1.50k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
1.50k
        return result;
421
1.50k
    }
422
157k
    bigfield result(ctx);
423
157k
    result.binary_basis_limbs[0].maximum_value =
424
157k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
157k
    result.binary_basis_limbs[1].maximum_value =
426
157k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
157k
    result.binary_basis_limbs[2].maximum_value =
428
157k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
157k
    result.binary_basis_limbs[3].maximum_value =
430
157k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
157k
    if constexpr (HasPlookup<Builder>) {
433
157k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
157k
            !is_constant() && !other.is_constant()) {
435
125k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
125k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
125k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
125k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
125k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
125k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
125k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
125k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
125k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
125k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
125k
            limbconst =
446
125k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
125k
                              other.prime_basis_limb
448
125k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
125k
            if (!limbconst) {
451
25.1k
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
25.1k
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
25.1k
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
25.1k
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
25.1k
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
25.1k
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
25.1k
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
25.1k
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
25.1k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
25.1k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
25.1k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
25.1k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
25.1k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
25.1k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
25.1k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
25.1k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
25.1k
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
25.1k
                          other.binary_basis_limbs[0].element.additive_constant);
469
25.1k
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
25.1k
                          other.binary_basis_limbs[1].element.additive_constant);
471
25.1k
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
25.1k
                          other.binary_basis_limbs[2].element.additive_constant);
473
25.1k
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
25.1k
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
25.1k
                uint32_t xp(prime_basis_limb.witness_index);
477
25.1k
                uint32_t yp(other.prime_basis_limb.witness_index);
478
25.1k
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
25.1k
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
25.1k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
25.1k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
25.1k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
25.1k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
25.1k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
25.1k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
25.1k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
25.1k
                return result;
488
25.1k
            }
489
125k
        }
490
157k
    }
491
492
131k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
131k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
131k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
131k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
131k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
131k
    return result;
498
157k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEplERKS6_
Line
Count
Source
411
127k
{
412
127k
    reduction_check();
413
127k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
127k
    Builder* ctx = context ? context : other.context;
416
417
127k
    if (is_constant() && other.is_constant()) {
418
1.50k
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
1.50k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
1.50k
        return result;
421
1.50k
    }
422
126k
    bigfield result(ctx);
423
126k
    result.binary_basis_limbs[0].maximum_value =
424
126k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
126k
    result.binary_basis_limbs[1].maximum_value =
426
126k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
126k
    result.binary_basis_limbs[2].maximum_value =
428
126k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
126k
    result.binary_basis_limbs[3].maximum_value =
430
126k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
126k
    if constexpr (HasPlookup<Builder>) {
433
126k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
126k
            !is_constant() && !other.is_constant()) {
435
99.9k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
99.9k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
99.9k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
99.9k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
99.9k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
99.9k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
99.9k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
99.9k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
99.9k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
99.9k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
99.9k
            limbconst =
446
99.9k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
99.9k
                              other.prime_basis_limb
448
99.9k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
99.9k
            if (!limbconst) {
451
25.0k
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
25.0k
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
25.0k
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
25.0k
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
25.0k
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
25.0k
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
25.0k
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
25.0k
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
25.0k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
25.0k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
25.0k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
25.0k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
25.0k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
25.0k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
25.0k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
25.0k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
25.0k
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
25.0k
                          other.binary_basis_limbs[0].element.additive_constant);
469
25.0k
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
25.0k
                          other.binary_basis_limbs[1].element.additive_constant);
471
25.0k
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
25.0k
                          other.binary_basis_limbs[2].element.additive_constant);
473
25.0k
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
25.0k
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
25.0k
                uint32_t xp(prime_basis_limb.witness_index);
477
25.0k
                uint32_t yp(other.prime_basis_limb.witness_index);
478
25.0k
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
25.0k
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
25.0k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
25.0k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
25.0k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
25.0k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
25.0k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
25.0k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
25.0k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
25.0k
                return result;
488
25.0k
            }
489
99.9k
        }
490
126k
    }
491
492
101k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
101k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
101k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
101k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
101k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
101k
    return result;
498
126k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEplERKS6_
Line
Count
Source
411
39
{
412
39
    reduction_check();
413
39
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
39
    Builder* ctx = context ? context : other.context;
416
417
39
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
39
    bigfield result(ctx);
423
39
    result.binary_basis_limbs[0].maximum_value =
424
39
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
39
    result.binary_basis_limbs[1].maximum_value =
426
39
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
39
    result.binary_basis_limbs[2].maximum_value =
428
39
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
39
    result.binary_basis_limbs[3].maximum_value =
430
39
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
39
    if constexpr (HasPlookup<Builder>) {
433
39
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
39
            !is_constant() && !other.is_constant()) {
435
30
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
30
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
30
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
30
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
30
            limbconst = limbconst || prime_basis_limb.is_constant();
440
30
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
30
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
30
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
30
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
30
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
30
            limbconst =
446
30
                limbconst || (prime_basis_limb.get_witness_index() ==
447
30
                              other.prime_basis_limb
448
30
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
30
            if (!limbconst) {
451
27
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
27
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
27
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
27
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
27
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
27
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
27
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
27
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
27
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
27
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
27
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
27
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
27
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
27
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
27
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
27
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
27
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
27
                          other.binary_basis_limbs[0].element.additive_constant);
469
27
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
27
                          other.binary_basis_limbs[1].element.additive_constant);
471
27
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
27
                          other.binary_basis_limbs[2].element.additive_constant);
473
27
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
27
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
27
                uint32_t xp(prime_basis_limb.witness_index);
477
27
                uint32_t yp(other.prime_basis_limb.witness_index);
478
27
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
27
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
27
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
27
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
27
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
27
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
27
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
27
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
27
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
27
                return result;
488
27
            }
489
30
        }
490
39
    }
491
492
12
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
12
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
12
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
12
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
12
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
12
    return result;
498
39
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEplERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EplERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEplERKS7_
Line
Count
Source
411
1.73k
{
412
1.73k
    reduction_check();
413
1.73k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
1.73k
    Builder* ctx = context ? context : other.context;
416
417
1.73k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
1.73k
    bigfield result(ctx);
423
1.73k
    result.binary_basis_limbs[0].maximum_value =
424
1.73k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
1.73k
    result.binary_basis_limbs[1].maximum_value =
426
1.73k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
1.73k
    result.binary_basis_limbs[2].maximum_value =
428
1.73k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
1.73k
    result.binary_basis_limbs[3].maximum_value =
430
1.73k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
1.73k
    if constexpr (HasPlookup<Builder>) {
433
1.73k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
1.73k
            !is_constant() && !other.is_constant()) {
435
1.36k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
1.36k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
1.36k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
1.36k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
1.36k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
1.36k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
1.36k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
1.36k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
1.36k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
1.36k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
1.36k
            limbconst =
446
1.36k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
1.36k
                              other.prime_basis_limb
448
1.36k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
1.36k
            if (!limbconst) {
451
18
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
18
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
18
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
18
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
18
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
18
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
18
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
18
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
18
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
18
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
18
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
18
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
18
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
18
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
18
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
18
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
18
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
18
                          other.binary_basis_limbs[0].element.additive_constant);
469
18
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
18
                          other.binary_basis_limbs[1].element.additive_constant);
471
18
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
18
                          other.binary_basis_limbs[2].element.additive_constant);
473
18
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
18
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
18
                uint32_t xp(prime_basis_limb.witness_index);
477
18
                uint32_t yp(other.prime_basis_limb.witness_index);
478
18
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
18
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
18
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
18
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
18
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
18
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
18
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
18
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
18
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
18
                return result;
488
18
            }
489
1.36k
        }
490
1.73k
    }
491
492
1.72k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
1.72k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
1.72k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
1.72k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
1.72k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
1.72k
    return result;
498
1.73k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEplERKS7_
Line
Count
Source
411
25
{
412
25
    reduction_check();
413
25
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
25
    Builder* ctx = context ? context : other.context;
416
417
25
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
25
    bigfield result(ctx);
423
25
    result.binary_basis_limbs[0].maximum_value =
424
25
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
25
    result.binary_basis_limbs[1].maximum_value =
426
25
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
25
    result.binary_basis_limbs[2].maximum_value =
428
25
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
25
    result.binary_basis_limbs[3].maximum_value =
430
25
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
25
    if constexpr (HasPlookup<Builder>) {
433
25
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
25
            !is_constant() && !other.is_constant()) {
435
25
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
25
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
25
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
25
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
25
            limbconst = limbconst || prime_basis_limb.is_constant();
440
25
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
25
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
25
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
25
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
25
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
25
            limbconst =
446
25
                limbconst || (prime_basis_limb.get_witness_index() ==
447
25
                              other.prime_basis_limb
448
25
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
25
            if (!limbconst) {
451
1
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
1
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
1
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
1
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
1
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
1
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
1
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
1
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
1
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
1
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
1
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
1
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
1
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
1
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
1
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
1
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
1
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
1
                          other.binary_basis_limbs[0].element.additive_constant);
469
1
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
1
                          other.binary_basis_limbs[1].element.additive_constant);
471
1
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
1
                          other.binary_basis_limbs[2].element.additive_constant);
473
1
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
1
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
1
                uint32_t xp(prime_basis_limb.witness_index);
477
1
                uint32_t yp(other.prime_basis_limb.witness_index);
478
1
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
1
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
1
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
1
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
1
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
1
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
1
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
1
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
1
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
1
                return result;
488
1
            }
489
25
        }
490
25
    }
491
492
24
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
24
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
24
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
24
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
24
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
24
    return result;
498
25
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEplERKS9_
Line
Count
Source
411
25.9k
{
412
25.9k
    reduction_check();
413
25.9k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
25.9k
    Builder* ctx = context ? context : other.context;
416
417
25.9k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
25.9k
    bigfield result(ctx);
423
25.9k
    result.binary_basis_limbs[0].maximum_value =
424
25.9k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
25.9k
    result.binary_basis_limbs[1].maximum_value =
426
25.9k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
25.9k
    result.binary_basis_limbs[2].maximum_value =
428
25.9k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
25.9k
    result.binary_basis_limbs[3].maximum_value =
430
25.9k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
25.9k
    if constexpr (HasPlookup<Builder>) {
433
25.9k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
25.9k
            !is_constant() && !other.is_constant()) {
435
20.9k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
20.9k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
20.9k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
20.9k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
20.9k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
20.9k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
20.9k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
20.9k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
20.9k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
20.9k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
20.9k
            limbconst =
446
20.9k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
20.9k
                              other.prime_basis_limb
448
20.9k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
20.9k
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
20.9k
        }
490
25.9k
    }
491
492
25.9k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
25.9k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
25.9k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
25.9k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
25.9k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
25.9k
    return result;
498
25.9k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEplERKS9_
Line
Count
Source
411
456
{
412
456
    reduction_check();
413
456
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
456
    Builder* ctx = context ? context : other.context;
416
417
456
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
456
    bigfield result(ctx);
423
456
    result.binary_basis_limbs[0].maximum_value =
424
456
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
456
    result.binary_basis_limbs[1].maximum_value =
426
456
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
456
    result.binary_basis_limbs[2].maximum_value =
428
456
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
456
    result.binary_basis_limbs[3].maximum_value =
430
456
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
456
    if constexpr (HasPlookup<Builder>) {
433
456
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
456
            !is_constant() && !other.is_constant()) {
435
456
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
456
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
456
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
456
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
456
            limbconst = limbconst || prime_basis_limb.is_constant();
440
456
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
456
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
456
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
456
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
456
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
456
            limbconst =
446
456
                limbconst || (prime_basis_limb.get_witness_index() ==
447
456
                              other.prime_basis_limb
448
456
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
456
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
456
        }
490
456
    }
491
492
456
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
456
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
456
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
456
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
456
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
456
    return result;
498
456
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEplERKS7_
Line
Count
Source
411
1.34k
{
412
1.34k
    reduction_check();
413
1.34k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
1.34k
    Builder* ctx = context ? context : other.context;
416
417
1.34k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
1.34k
    bigfield result(ctx);
423
1.34k
    result.binary_basis_limbs[0].maximum_value =
424
1.34k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
1.34k
    result.binary_basis_limbs[1].maximum_value =
426
1.34k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
1.34k
    result.binary_basis_limbs[2].maximum_value =
428
1.34k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
1.34k
    result.binary_basis_limbs[3].maximum_value =
430
1.34k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
1.34k
    if constexpr (HasPlookup<Builder>) {
433
1.34k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
1.34k
            !is_constant() && !other.is_constant()) {
435
1.30k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
1.30k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
1.30k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
1.30k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
1.30k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
1.30k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
1.30k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
1.30k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
1.30k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
1.30k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
1.30k
            limbconst =
446
1.30k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
1.30k
                              other.prime_basis_limb
448
1.30k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
1.30k
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
1.30k
        }
490
1.34k
    }
491
492
1.34k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
1.34k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
1.34k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
1.34k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
1.34k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
1.34k
    return result;
498
1.34k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEplERKS7_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEplERKS9_
Line
Count
Source
411
1.07k
{
412
1.07k
    reduction_check();
413
1.07k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
1.07k
    Builder* ctx = context ? context : other.context;
416
417
1.07k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
1.07k
    bigfield result(ctx);
423
1.07k
    result.binary_basis_limbs[0].maximum_value =
424
1.07k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
1.07k
    result.binary_basis_limbs[1].maximum_value =
426
1.07k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
1.07k
    result.binary_basis_limbs[2].maximum_value =
428
1.07k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
1.07k
    result.binary_basis_limbs[3].maximum_value =
430
1.07k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
1.07k
    if constexpr (HasPlookup<Builder>) {
433
1.07k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
1.07k
            !is_constant() && !other.is_constant()) {
435
1.04k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
1.04k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
1.04k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
1.04k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
1.04k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
1.04k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
1.04k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
1.04k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
1.04k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
1.04k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
1.04k
            limbconst =
446
1.04k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
1.04k
                              other.prime_basis_limb
448
1.04k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
1.04k
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
1.04k
        }
490
1.07k
    }
491
492
1.07k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
1.07k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
1.07k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
1.07k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
1.07k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
1.07k
    return result;
498
1.07k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEplERKS9_
499
500
/**
501
 * @brief Create constraints for summing three
502
 * bigfield elements efficiently
503
 *
504
 * @tparam Builder
505
 * @tparam T
506
 * @param add_a
507
 * @param add_b
508
 * @return The sum of three terms
509
 */
510
template <typename Builder, typename T>
511
bigfield<Builder, T> bigfield<Builder, T>::add_two(const bigfield& add_a, const bigfield& add_b) const
512
0
{
513
0
    reduction_check();
514
0
    add_a.reduction_check();
515
0
    add_b.reduction_check();
516
517
0
    Builder* ctx = (context == nullptr) ? (add_a.context == nullptr ? add_b.context : add_a.context) : context;
518
519
0
    if (is_constant() && add_a.is_constant() && add_b.is_constant()) {
520
0
        auto result = bigfield(ctx, uint256_t((get_value() + add_a.get_value() + add_b.get_value()) % modulus_u512));
521
0
        result.set_origin_tag(OriginTag(this->get_origin_tag(), add_a.get_origin_tag(), add_b.get_origin_tag()));
522
0
        return result;
523
0
    }
524
525
0
    bigfield result(ctx);
526
0
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value +
527
0
                                                 add_a.binary_basis_limbs[0].maximum_value +
528
0
                                                 add_b.binary_basis_limbs[0].maximum_value;
529
0
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value +
530
0
                                                 add_a.binary_basis_limbs[1].maximum_value +
531
0
                                                 add_b.binary_basis_limbs[1].maximum_value;
532
0
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value +
533
0
                                                 add_a.binary_basis_limbs[2].maximum_value +
534
0
                                                 add_b.binary_basis_limbs[2].maximum_value;
535
0
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value +
536
0
                                                 add_a.binary_basis_limbs[3].maximum_value +
537
0
                                                 add_b.binary_basis_limbs[3].maximum_value;
538
539
0
    result.binary_basis_limbs[0].element =
540
0
        binary_basis_limbs[0].element.add_two(add_a.binary_basis_limbs[0].element, add_b.binary_basis_limbs[0].element);
541
0
    result.binary_basis_limbs[1].element =
542
0
        binary_basis_limbs[1].element.add_two(add_a.binary_basis_limbs[1].element, add_b.binary_basis_limbs[1].element);
543
0
    result.binary_basis_limbs[2].element =
544
0
        binary_basis_limbs[2].element.add_two(add_a.binary_basis_limbs[2].element, add_b.binary_basis_limbs[2].element);
545
0
    result.binary_basis_limbs[3].element =
546
0
        binary_basis_limbs[3].element.add_two(add_a.binary_basis_limbs[3].element, add_b.binary_basis_limbs[3].element);
547
0
    result.prime_basis_limb = prime_basis_limb.add_two(add_a.prime_basis_limb, add_b.prime_basis_limb);
548
0
    result.set_origin_tag(OriginTag(this->get_origin_tag(), add_a.get_origin_tag(), add_b.get_origin_tag()));
549
0
    return result;
550
0
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE7add_twoERKS6_S8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE7add_twoERKS6_S8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE7add_twoERKS8_SA_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE7add_twoERKS9_SB_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE7add_twoERKS9_SB_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE7add_twoERKS9_SB_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE7add_twoERKS9_SB_
551
552
// to make sure we don't go to negative values, add p before subtracting other
553
/**
554
 * Subtraction operator.
555
 *
556
 * Like operator+, we use lazy reduction techniques to save on field reductions.
557
 *
558
 * Instead of computing `*this - other`, we compute offset X and compute:
559
 * `*this + X - other`
560
 * This ensures we do not underflow!
561
 *
562
 * Offset `X` will be a multiple of our bigfield modulus `p`
563
 *
564
 * i.e `X = m * p`
565
 *
566
 * It is NOT enough to ensure that the integer value of `*this + X - other` does not underflow.
567
 * We must ALSO ensure that each LIMB of the result does not underflow
568
 *
569
 * We must compute the MINIMUM value of `m` that ensures that none of the bigfield limbs will underflow!
570
 *
571
 * i.e. We must compute the MINIMUM value of `m` such that, for each limb `i`, the following result is positive:
572
 *
573
 * *this.limb[i] + X.limb[i] - other.limb[i]
574
 **/
575
template <typename Builder, typename T>
576
bigfield<Builder, T> bigfield<Builder, T>::operator-(const bigfield& other) const
577
1.77M
{
578
1.77M
    Builder* ctx = context ? context : other.context;
579
1.77M
    reduction_check();
580
1.77M
    other.reduction_check();
581
582
1.77M
    if (is_constant() && other.is_constant()) {
583
8.45k
        uint512_t left = get_value() % modulus_u512;
584
8.45k
        uint512_t right = other.get_value() % modulus_u512;
585
8.45k
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
8.45k
        auto result = bigfield(ctx, uint256_t(out.lo));
588
8.45k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
8.45k
        return result;
590
8.45k
    }
591
592
1.76M
    if (other.is_constant()) {
593
10.5k
        uint512_t right = other.get_value() % modulus_u512;
594
10.5k
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
10.5k
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
10.5k
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
1.75M
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
1.75M
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
1.75M
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
1.75M
    uint256_t limb_1_maximum_value =
632
1.75M
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
1.75M
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
1.75M
    uint256_t limb_2_maximum_value =
637
1.75M
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
1.75M
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
1.75M
    uint256_t limb_3_maximum_value =
641
1.75M
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
1.75M
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
3.58M
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
1.82M
        constant_to_add += modulus_u512;
655
1.82M
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
1.75M
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
1.75M
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
1.75M
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
1.75M
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
1.75M
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
1.75M
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
1.75M
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
1.75M
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
1.75M
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
1.75M
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
1.75M
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
1.75M
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
1.75M
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
1.75M
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
1.75M
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
1.75M
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
1.75M
    if constexpr (HasPlookup<Builder>) {
702
1.75M
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
1.75M
            !is_constant() && !other.is_constant()) {
704
768k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
768k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
768k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
768k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
768k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
768k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
768k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
768k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
768k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
768k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
768k
            limbconst =
715
768k
                limbconst ||
716
768k
                (prime_basis_limb.witness_index ==
717
768k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
768k
            if (!limbconst) {
720
768k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
768k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
768k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
768k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
768k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
768k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
768k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
768k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
768k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
768k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
768k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
768k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
768k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
768k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
768k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
768k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
768k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
768k
                          other.binary_basis_limbs[0].element.additive_constant);
738
768k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
768k
                          other.binary_basis_limbs[1].element.additive_constant);
740
768k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
768k
                          other.binary_basis_limbs[2].element.additive_constant);
742
768k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
768k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
768k
                uint32_t xp(prime_basis_limb.witness_index);
746
768k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
768k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
768k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
768k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
768k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
768k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
768k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
768k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
768k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
768k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
768k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
768k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
768k
                return result;
762
768k
            }
763
768k
        }
764
1.75M
    }
765
766
986k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
986k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
986k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
986k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
986k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
986k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
986k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
986k
    result.prime_basis_limb -= other.prime_basis_limb;
778
986k
    return result;
779
1.75M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEmiERKS6_
Line
Count
Source
577
1.61M
{
578
1.61M
    Builder* ctx = context ? context : other.context;
579
1.61M
    reduction_check();
580
1.61M
    other.reduction_check();
581
582
1.61M
    if (is_constant() && other.is_constant()) {
583
8.00k
        uint512_t left = get_value() % modulus_u512;
584
8.00k
        uint512_t right = other.get_value() % modulus_u512;
585
8.00k
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
8.00k
        auto result = bigfield(ctx, uint256_t(out.lo));
588
8.00k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
8.00k
        return result;
590
8.00k
    }
591
592
1.60M
    if (other.is_constant()) {
593
10.4k
        uint512_t right = other.get_value() % modulus_u512;
594
10.4k
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
10.4k
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
10.4k
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
1.59M
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
1.59M
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
1.59M
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
1.59M
    uint256_t limb_1_maximum_value =
632
1.59M
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
1.59M
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
1.59M
    uint256_t limb_2_maximum_value =
637
1.59M
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
1.59M
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
1.59M
    uint256_t limb_3_maximum_value =
641
1.59M
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
1.59M
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
3.26M
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
1.66M
        constant_to_add += modulus_u512;
655
1.66M
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
1.59M
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
1.59M
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
1.59M
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
1.59M
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
1.59M
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
1.59M
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
1.59M
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
1.59M
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
1.59M
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
1.59M
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
1.59M
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
1.59M
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
1.59M
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
1.59M
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
1.59M
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
1.59M
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
1.59M
    if constexpr (HasPlookup<Builder>) {
702
1.59M
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
1.59M
            !is_constant() && !other.is_constant()) {
704
706k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
706k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
706k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
706k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
706k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
706k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
706k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
706k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
706k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
706k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
706k
            limbconst =
715
706k
                limbconst ||
716
706k
                (prime_basis_limb.witness_index ==
717
706k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
706k
            if (!limbconst) {
720
706k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
706k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
706k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
706k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
706k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
706k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
706k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
706k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
706k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
706k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
706k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
706k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
706k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
706k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
706k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
706k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
706k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
706k
                          other.binary_basis_limbs[0].element.additive_constant);
738
706k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
706k
                          other.binary_basis_limbs[1].element.additive_constant);
740
706k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
706k
                          other.binary_basis_limbs[2].element.additive_constant);
742
706k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
706k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
706k
                uint32_t xp(prime_basis_limb.witness_index);
746
706k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
706k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
706k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
706k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
706k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
706k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
706k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
706k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
706k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
706k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
706k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
706k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
706k
                return result;
762
706k
            }
763
706k
        }
764
1.59M
    }
765
766
892k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
892k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
892k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
892k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
892k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
892k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
892k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
892k
    result.prime_basis_limb -= other.prime_basis_limb;
778
892k
    return result;
779
1.59M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEmiERKS6_
Line
Count
Source
577
653
{
578
653
    Builder* ctx = context ? context : other.context;
579
653
    reduction_check();
580
653
    other.reduction_check();
581
582
653
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
653
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
653
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
653
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
653
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
653
    uint256_t limb_1_maximum_value =
632
653
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
653
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
653
    uint256_t limb_2_maximum_value =
637
653
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
653
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
653
    uint256_t limb_3_maximum_value =
641
653
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
653
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
1.34k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
690
        constant_to_add += modulus_u512;
655
690
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
653
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
653
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
653
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
653
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
653
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
653
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
653
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
653
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
653
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
653
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
653
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
653
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
653
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
653
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
653
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
653
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
653
    if constexpr (HasPlookup<Builder>) {
702
653
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
653
            !is_constant() && !other.is_constant()) {
704
641
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
641
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
641
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
641
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
641
            limbconst = limbconst || prime_basis_limb.is_constant();
709
641
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
641
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
641
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
641
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
641
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
641
            limbconst =
715
641
                limbconst ||
716
641
                (prime_basis_limb.witness_index ==
717
641
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
641
            if (!limbconst) {
720
641
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
641
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
641
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
641
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
641
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
641
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
641
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
641
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
641
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
641
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
641
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
641
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
641
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
641
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
641
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
641
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
641
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
641
                          other.binary_basis_limbs[0].element.additive_constant);
738
641
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
641
                          other.binary_basis_limbs[1].element.additive_constant);
740
641
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
641
                          other.binary_basis_limbs[2].element.additive_constant);
742
641
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
641
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
641
                uint32_t xp(prime_basis_limb.witness_index);
746
641
                uint32_t yp(other.prime_basis_limb.witness_index);
747
641
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
641
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
641
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
641
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
641
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
641
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
641
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
641
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
641
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
641
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
641
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
641
                return result;
762
641
            }
763
641
        }
764
653
    }
765
766
12
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
12
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
12
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
12
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
12
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
12
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
12
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
12
    result.prime_basis_limb -= other.prime_basis_limb;
778
12
    return result;
779
653
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEmiERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EmiERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEmiERKS7_
Line
Count
Source
577
7.23k
{
578
7.23k
    Builder* ctx = context ? context : other.context;
579
7.23k
    reduction_check();
580
7.23k
    other.reduction_check();
581
582
7.23k
    if (is_constant() && other.is_constant()) {
583
18
        uint512_t left = get_value() % modulus_u512;
584
18
        uint512_t right = other.get_value() % modulus_u512;
585
18
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
18
        auto result = bigfield(ctx, uint256_t(out.lo));
588
18
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
18
        return result;
590
18
    }
591
592
7.21k
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
7.21k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
7.21k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
7.21k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
7.21k
    uint256_t limb_1_maximum_value =
632
7.21k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
7.21k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
7.21k
    uint256_t limb_2_maximum_value =
637
7.21k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
7.21k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
7.21k
    uint256_t limb_3_maximum_value =
641
7.21k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
7.21k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
14.9k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
7.75k
        constant_to_add += modulus_u512;
655
7.75k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
7.21k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
7.21k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
7.21k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
7.21k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
7.21k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
7.21k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
7.21k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
7.21k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
7.21k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
7.21k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
7.21k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
7.21k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
7.21k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
7.21k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
7.21k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
7.21k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
7.21k
    if constexpr (HasPlookup<Builder>) {
702
7.21k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
7.21k
            !is_constant() && !other.is_constant()) {
704
2.83k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
2.83k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
2.83k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
2.83k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
2.83k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
2.83k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
2.83k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
2.83k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
2.83k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
2.83k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
2.83k
            limbconst =
715
2.83k
                limbconst ||
716
2.83k
                (prime_basis_limb.witness_index ==
717
2.83k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
2.83k
            if (!limbconst) {
720
2.83k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
2.83k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
2.83k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
2.83k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
2.83k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
2.83k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
2.83k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
2.83k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
2.83k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
2.83k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
2.83k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
2.83k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
2.83k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
2.83k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
2.83k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
2.83k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
2.83k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
2.83k
                          other.binary_basis_limbs[0].element.additive_constant);
738
2.83k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
2.83k
                          other.binary_basis_limbs[1].element.additive_constant);
740
2.83k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
2.83k
                          other.binary_basis_limbs[2].element.additive_constant);
742
2.83k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
2.83k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
2.83k
                uint32_t xp(prime_basis_limb.witness_index);
746
2.83k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
2.83k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
2.83k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
2.83k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
2.83k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
2.83k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
2.83k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
2.83k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
2.83k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
2.83k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
2.83k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
2.83k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
2.83k
                return result;
762
2.83k
            }
763
2.83k
        }
764
7.21k
    }
765
766
4.38k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
4.38k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
4.38k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
4.38k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
4.38k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
4.38k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
4.38k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
4.38k
    result.prime_basis_limb -= other.prime_basis_limb;
778
4.38k
    return result;
779
7.21k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEmiERKS7_
Line
Count
Source
577
26
{
578
26
    Builder* ctx = context ? context : other.context;
579
26
    reduction_check();
580
26
    other.reduction_check();
581
582
26
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
26
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
26
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
26
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
26
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
26
    uint256_t limb_1_maximum_value =
632
26
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
26
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
26
    uint256_t limb_2_maximum_value =
637
26
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
26
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
26
    uint256_t limb_3_maximum_value =
641
26
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
26
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
28
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
2
        constant_to_add += modulus_u512;
655
2
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
26
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
26
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
26
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
26
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
26
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
26
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
26
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
26
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
26
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
26
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
26
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
26
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
26
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
26
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
26
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
26
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
26
    if constexpr (HasPlookup<Builder>) {
702
26
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
26
            !is_constant() && !other.is_constant()) {
704
26
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
26
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
26
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
26
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
26
            limbconst = limbconst || prime_basis_limb.is_constant();
709
26
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
26
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
26
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
26
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
26
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
26
            limbconst =
715
26
                limbconst ||
716
26
                (prime_basis_limb.witness_index ==
717
26
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
26
            if (!limbconst) {
720
26
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
26
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
26
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
26
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
26
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
26
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
26
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
26
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
26
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
26
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
26
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
26
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
26
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
26
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
26
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
26
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
26
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
26
                          other.binary_basis_limbs[0].element.additive_constant);
738
26
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
26
                          other.binary_basis_limbs[1].element.additive_constant);
740
26
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
26
                          other.binary_basis_limbs[2].element.additive_constant);
742
26
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
26
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
26
                uint32_t xp(prime_basis_limb.witness_index);
746
26
                uint32_t yp(other.prime_basis_limb.witness_index);
747
26
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
26
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
26
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
26
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
26
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
26
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
26
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
26
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
26
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
26
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
26
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
26
                return result;
762
26
            }
763
26
        }
764
26
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
26
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEmiERKS9_
Line
Count
Source
577
128k
{
578
128k
    Builder* ctx = context ? context : other.context;
579
128k
    reduction_check();
580
128k
    other.reduction_check();
581
582
128k
    if (is_constant() && other.is_constant()) {
583
342
        uint512_t left = get_value() % modulus_u512;
584
342
        uint512_t right = other.get_value() % modulus_u512;
585
342
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
342
        auto result = bigfield(ctx, uint256_t(out.lo));
588
342
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
342
        return result;
590
342
    }
591
592
127k
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
127k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
127k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
127k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
127k
    uint256_t limb_1_maximum_value =
632
127k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
127k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
127k
    uint256_t limb_2_maximum_value =
637
127k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
127k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
127k
    uint256_t limb_3_maximum_value =
641
127k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
127k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
263k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
136k
        constant_to_add += modulus_u512;
655
136k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
127k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
127k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
127k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
127k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
127k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
127k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
127k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
127k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
127k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
127k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
127k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
127k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
127k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
127k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
127k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
127k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
127k
    if constexpr (HasPlookup<Builder>) {
702
127k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
127k
            !is_constant() && !other.is_constant()) {
704
50.3k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
50.3k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
50.3k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
50.3k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
50.3k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
50.3k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
50.3k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
50.3k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
50.3k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
50.3k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
50.3k
            limbconst =
715
50.3k
                limbconst ||
716
50.3k
                (prime_basis_limb.witness_index ==
717
50.3k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
50.3k
            if (!limbconst) {
720
50.3k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
50.3k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
50.3k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
50.3k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
50.3k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
50.3k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
50.3k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
50.3k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
50.3k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
50.3k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
50.3k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
50.3k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
50.3k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
50.3k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
50.3k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
50.3k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
50.3k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
50.3k
                          other.binary_basis_limbs[0].element.additive_constant);
738
50.3k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
50.3k
                          other.binary_basis_limbs[1].element.additive_constant);
740
50.3k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
50.3k
                          other.binary_basis_limbs[2].element.additive_constant);
742
50.3k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
50.3k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
50.3k
                uint32_t xp(prime_basis_limb.witness_index);
746
50.3k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
50.3k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
50.3k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
50.3k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
50.3k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
50.3k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
50.3k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
50.3k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
50.3k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
50.3k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
50.3k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
50.3k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
50.3k
                return result;
762
50.3k
            }
763
50.3k
        }
764
127k
    }
765
766
77.5k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
77.5k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
77.5k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
77.5k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
77.5k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
77.5k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
77.5k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
77.5k
    result.prime_basis_limb -= other.prime_basis_limb;
778
77.5k
    return result;
779
127k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEmiERKS9_
Line
Count
Source
577
456
{
578
456
    Builder* ctx = context ? context : other.context;
579
456
    reduction_check();
580
456
    other.reduction_check();
581
582
456
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
456
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
456
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
456
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
456
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
456
    uint256_t limb_1_maximum_value =
632
456
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
456
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
456
    uint256_t limb_2_maximum_value =
637
456
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
456
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
456
    uint256_t limb_3_maximum_value =
641
456
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
456
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
456
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
0
        constant_to_add += modulus_u512;
655
0
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
456
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
456
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
456
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
456
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
456
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
456
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
456
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
456
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
456
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
456
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
456
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
456
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
456
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
456
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
456
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
456
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
456
    if constexpr (HasPlookup<Builder>) {
702
456
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
456
            !is_constant() && !other.is_constant()) {
704
456
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
456
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
456
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
456
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
456
            limbconst = limbconst || prime_basis_limb.is_constant();
709
456
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
456
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
456
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
456
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
456
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
456
            limbconst =
715
456
                limbconst ||
716
456
                (prime_basis_limb.witness_index ==
717
456
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
456
            if (!limbconst) {
720
456
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
456
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
456
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
456
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
456
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
456
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
456
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
456
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
456
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
456
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
456
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
456
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
456
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
456
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
456
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
456
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
456
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
456
                          other.binary_basis_limbs[0].element.additive_constant);
738
456
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
456
                          other.binary_basis_limbs[1].element.additive_constant);
740
456
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
456
                          other.binary_basis_limbs[2].element.additive_constant);
742
456
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
456
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
456
                uint32_t xp(prime_basis_limb.witness_index);
746
456
                uint32_t yp(other.prime_basis_limb.witness_index);
747
456
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
456
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
456
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
456
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
456
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
456
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
456
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
456
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
456
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
456
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
456
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
456
                return result;
762
456
            }
763
456
        }
764
456
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
456
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEmiERKS7_
Line
Count
Source
577
11.4k
{
578
11.4k
    Builder* ctx = context ? context : other.context;
579
11.4k
    reduction_check();
580
11.4k
    other.reduction_check();
581
582
11.4k
    if (is_constant() && other.is_constant()) {
583
50
        uint512_t left = get_value() % modulus_u512;
584
50
        uint512_t right = other.get_value() % modulus_u512;
585
50
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
50
        auto result = bigfield(ctx, uint256_t(out.lo));
588
50
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
50
        return result;
590
50
    }
591
592
11.3k
    if (other.is_constant()) {
593
15
        uint512_t right = other.get_value() % modulus_u512;
594
15
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
15
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
15
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
11.3k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
11.3k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
11.3k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
11.3k
    uint256_t limb_1_maximum_value =
632
11.3k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
11.3k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
11.3k
    uint256_t limb_2_maximum_value =
637
11.3k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
11.3k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
11.3k
    uint256_t limb_3_maximum_value =
641
11.3k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
11.3k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
23.0k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
11.6k
        constant_to_add += modulus_u512;
655
11.6k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
11.3k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
11.3k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
11.3k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
11.3k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
11.3k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
11.3k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
11.3k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
11.3k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
11.3k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
11.3k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
11.3k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
11.3k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
11.3k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
11.3k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
11.3k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
11.3k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
11.3k
    if constexpr (HasPlookup<Builder>) {
702
11.3k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
11.3k
            !is_constant() && !other.is_constant()) {
704
4.50k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
4.50k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
4.50k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
4.50k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
4.50k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
4.50k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
4.50k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
4.50k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
4.50k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
4.50k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
4.50k
            limbconst =
715
4.50k
                limbconst ||
716
4.50k
                (prime_basis_limb.witness_index ==
717
4.50k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
4.50k
            if (!limbconst) {
720
4.50k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
4.50k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
4.50k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
4.50k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
4.50k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
4.50k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
4.50k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
4.50k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
4.50k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
4.50k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
4.50k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
4.50k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
4.50k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
4.50k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
4.50k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
4.50k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
4.50k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
4.50k
                          other.binary_basis_limbs[0].element.additive_constant);
738
4.50k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
4.50k
                          other.binary_basis_limbs[1].element.additive_constant);
740
4.50k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
4.50k
                          other.binary_basis_limbs[2].element.additive_constant);
742
4.50k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
4.50k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
4.50k
                uint32_t xp(prime_basis_limb.witness_index);
746
4.50k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
4.50k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
4.50k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
4.50k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
4.50k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
4.50k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
4.50k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
4.50k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
4.50k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
4.50k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
4.50k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
4.50k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
4.50k
                return result;
762
4.50k
            }
763
4.50k
        }
764
11.3k
    }
765
766
6.83k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
6.83k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
6.83k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
6.83k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
6.83k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
6.83k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
6.83k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
6.83k
    result.prime_basis_limb -= other.prime_basis_limb;
778
6.83k
    return result;
779
11.3k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEmiERKS7_
Line
Count
Source
577
20
{
578
20
    Builder* ctx = context ? context : other.context;
579
20
    reduction_check();
580
20
    other.reduction_check();
581
582
20
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
20
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
20
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
20
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
20
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
20
    uint256_t limb_1_maximum_value =
632
20
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
20
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
20
    uint256_t limb_2_maximum_value =
637
20
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
20
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
20
    uint256_t limb_3_maximum_value =
641
20
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
20
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
40
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
20
        constant_to_add += modulus_u512;
655
20
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
20
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
20
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
20
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
20
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
20
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
20
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
20
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
20
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
20
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
20
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
20
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
20
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
20
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
20
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
20
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
20
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
20
    if constexpr (HasPlookup<Builder>) {
702
20
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
20
            !is_constant() && !other.is_constant()) {
704
20
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
20
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
20
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
20
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
20
            limbconst = limbconst || prime_basis_limb.is_constant();
709
20
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
20
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
20
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
20
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
20
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
20
            limbconst =
715
20
                limbconst ||
716
20
                (prime_basis_limb.witness_index ==
717
20
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
20
            if (!limbconst) {
720
20
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
20
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
20
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
20
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
20
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
20
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
20
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
20
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
20
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
20
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
20
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
20
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
20
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
20
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
20
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
20
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
20
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
20
                          other.binary_basis_limbs[0].element.additive_constant);
738
20
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
20
                          other.binary_basis_limbs[1].element.additive_constant);
740
20
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
20
                          other.binary_basis_limbs[2].element.additive_constant);
742
20
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
20
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
20
                uint32_t xp(prime_basis_limb.witness_index);
746
20
                uint32_t yp(other.prime_basis_limb.witness_index);
747
20
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
20
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
20
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
20
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
20
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
20
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
20
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
20
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
20
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
20
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
20
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
20
                return result;
762
20
            }
763
20
        }
764
20
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
20
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEmiERKS9_
Line
Count
Source
577
9.12k
{
578
9.12k
    Builder* ctx = context ? context : other.context;
579
9.12k
    reduction_check();
580
9.12k
    other.reduction_check();
581
582
9.12k
    if (is_constant() && other.is_constant()) {
583
40
        uint512_t left = get_value() % modulus_u512;
584
40
        uint512_t right = other.get_value() % modulus_u512;
585
40
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
40
        auto result = bigfield(ctx, uint256_t(out.lo));
588
40
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
40
        return result;
590
40
    }
591
592
9.08k
    if (other.is_constant()) {
593
12
        uint512_t right = other.get_value() % modulus_u512;
594
12
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
12
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
12
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
9.07k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
9.07k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
9.07k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
9.07k
    uint256_t limb_1_maximum_value =
632
9.07k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
9.07k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
9.07k
    uint256_t limb_2_maximum_value =
637
9.07k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
9.07k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
9.07k
    uint256_t limb_3_maximum_value =
641
9.07k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
9.07k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
18.4k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
9.33k
        constant_to_add += modulus_u512;
655
9.33k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
9.07k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
9.07k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
9.07k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
9.07k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
9.07k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
9.07k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
9.07k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
9.07k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
9.07k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
9.07k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
9.07k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
9.07k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
9.07k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
9.07k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
9.07k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
9.07k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
9.07k
    if constexpr (HasPlookup<Builder>) {
702
9.07k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
9.07k
            !is_constant() && !other.is_constant()) {
704
3.60k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
3.60k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
3.60k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
3.60k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
3.60k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
3.60k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
3.60k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
3.60k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
3.60k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
3.60k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
3.60k
            limbconst =
715
3.60k
                limbconst ||
716
3.60k
                (prime_basis_limb.witness_index ==
717
3.60k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
3.60k
            if (!limbconst) {
720
3.60k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
3.60k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
3.60k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
3.60k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
3.60k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
3.60k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
3.60k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
3.60k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
3.60k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
3.60k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
3.60k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
3.60k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
3.60k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
3.60k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
3.60k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
3.60k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
3.60k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
3.60k
                          other.binary_basis_limbs[0].element.additive_constant);
738
3.60k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
3.60k
                          other.binary_basis_limbs[1].element.additive_constant);
740
3.60k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
3.60k
                          other.binary_basis_limbs[2].element.additive_constant);
742
3.60k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
3.60k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
3.60k
                uint32_t xp(prime_basis_limb.witness_index);
746
3.60k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
3.60k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
3.60k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
3.60k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
3.60k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
3.60k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
3.60k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
3.60k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
3.60k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
3.60k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
3.60k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
3.60k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
3.60k
                return result;
762
3.60k
            }
763
3.60k
        }
764
9.07k
    }
765
766
5.46k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
5.46k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
5.46k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
5.46k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
5.46k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
5.46k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
5.46k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
5.46k
    result.prime_basis_limb -= other.prime_basis_limb;
778
5.46k
    return result;
779
9.07k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEmiERKS9_
Line
Count
Source
577
16
{
578
16
    Builder* ctx = context ? context : other.context;
579
16
    reduction_check();
580
16
    other.reduction_check();
581
582
16
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
16
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
16
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
16
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
16
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
16
    uint256_t limb_1_maximum_value =
632
16
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
16
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
16
    uint256_t limb_2_maximum_value =
637
16
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
16
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
16
    uint256_t limb_3_maximum_value =
641
16
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
16
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
32
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
16
        constant_to_add += modulus_u512;
655
16
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
16
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
16
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
16
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
16
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
16
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
16
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
16
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
16
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
16
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
16
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
16
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
16
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
16
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
16
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
16
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
16
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
16
    if constexpr (HasPlookup<Builder>) {
702
16
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
16
            !is_constant() && !other.is_constant()) {
704
16
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
16
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
16
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
16
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
16
            limbconst = limbconst || prime_basis_limb.is_constant();
709
16
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
16
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
16
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
16
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
16
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
16
            limbconst =
715
16
                limbconst ||
716
16
                (prime_basis_limb.witness_index ==
717
16
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
16
            if (!limbconst) {
720
16
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
16
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
16
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
16
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
16
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
16
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
16
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
16
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
16
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
16
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
16
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
16
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
16
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
16
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
16
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
16
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
16
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
16
                          other.binary_basis_limbs[0].element.additive_constant);
738
16
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
16
                          other.binary_basis_limbs[1].element.additive_constant);
740
16
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
16
                          other.binary_basis_limbs[2].element.additive_constant);
742
16
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
16
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
16
                uint32_t xp(prime_basis_limb.witness_index);
746
16
                uint32_t yp(other.prime_basis_limb.witness_index);
747
16
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
16
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
16
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
16
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
16
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
16
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
16
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
16
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
16
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
16
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
16
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
16
                return result;
762
16
            }
763
16
        }
764
16
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
16
}
780
781
/**
782
 * Evaluate a non-native field multiplication: (a * b = c mod p) where p == target_basis.modulus
783
 *
784
 * We compute quotient term `q` and remainder `c` and evaluate that:
785
 *
786
 * a * b - q * p - c = 0 mod modulus_u512 (binary basis modulus, currently 2**272)
787
 * a * b - q * p - c = 0 mod circuit modulus
788
 **/
789
template <typename Builder, typename T>
790
bigfield<Builder, T> bigfield<Builder, T>::operator*(const bigfield& other) const
791
205k
{
792
    // First we do basic reduction checks of individual elements
793
205k
    reduction_check();
794
205k
    other.reduction_check();
795
205k
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
205k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
205k
    bigfield remainder;
799
205k
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
205k
    if (is_constant() && other.is_constant()) {
802
3.58k
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
3.58k
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
3.58k
        return remainder;
805
202k
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
202k
        auto [reduction_required, num_quotient_bits] =
813
202k
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
202k
        if (reduction_required) {
815
1
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
1
            } else {
818
1
                other.self_reduce();
819
1
            }
820
1
            return (*this).operator*(other);
821
1
        }
822
202k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
202k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
202k
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
202k
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
202k
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
202k
    return remainder;
831
205k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEmlERKS6_
Line
Count
Source
791
200k
{
792
    // First we do basic reduction checks of individual elements
793
200k
    reduction_check();
794
200k
    other.reduction_check();
795
200k
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
200k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
200k
    bigfield remainder;
799
200k
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
200k
    if (is_constant() && other.is_constant()) {
802
3.58k
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
3.58k
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
3.58k
        return remainder;
805
197k
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
197k
        auto [reduction_required, num_quotient_bits] =
813
197k
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
197k
        if (reduction_required) {
815
1
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
1
            } else {
818
1
                other.self_reduce();
819
1
            }
820
1
            return (*this).operator*(other);
821
1
        }
822
197k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
197k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
197k
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
197k
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
197k
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
197k
    return remainder;
831
200k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEmlERKS6_
Line
Count
Source
791
38
{
792
    // First we do basic reduction checks of individual elements
793
38
    reduction_check();
794
38
    other.reduction_check();
795
38
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
38
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
38
    bigfield remainder;
799
38
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
38
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
38
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
38
        auto [reduction_required, num_quotient_bits] =
813
38
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
38
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
38
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
38
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
38
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
38
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
38
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
38
    return remainder;
831
38
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEmlERKS8_
Line
Count
Source
791
20
{
792
    // First we do basic reduction checks of individual elements
793
20
    reduction_check();
794
20
    other.reduction_check();
795
20
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
20
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
20
    bigfield remainder;
799
20
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
20
    if (is_constant() && other.is_constant()) {
802
4
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
4
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
4
        return remainder;
805
16
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
16
        auto [reduction_required, num_quotient_bits] =
813
16
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
16
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
16
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
16
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
16
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
16
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
16
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
16
    return remainder;
831
20
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EmlERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEmlERKS7_
Line
Count
Source
791
246
{
792
    // First we do basic reduction checks of individual elements
793
246
    reduction_check();
794
246
    other.reduction_check();
795
246
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
246
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
246
    bigfield remainder;
799
246
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
246
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
246
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
246
        auto [reduction_required, num_quotient_bits] =
813
246
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
246
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
246
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
246
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
246
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
246
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
246
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
246
    return remainder;
831
246
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEmlERKS7_
Line
Count
Source
791
1
{
792
    // First we do basic reduction checks of individual elements
793
1
    reduction_check();
794
1
    other.reduction_check();
795
1
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
1
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
1
    bigfield remainder;
799
1
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
1
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
1
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
1
        auto [reduction_required, num_quotient_bits] =
813
1
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
1
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
1
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
1
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
1
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
1
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
1
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
1
    return remainder;
831
1
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEmlERKS9_
Line
Count
Source
791
4.67k
{
792
    // First we do basic reduction checks of individual elements
793
4.67k
    reduction_check();
794
4.67k
    other.reduction_check();
795
4.67k
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
4.67k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
4.67k
    bigfield remainder;
799
4.67k
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
4.67k
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
4.67k
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
4.67k
        auto [reduction_required, num_quotient_bits] =
813
4.67k
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
4.67k
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
4.67k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
4.67k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
4.67k
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
4.67k
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
4.67k
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
4.67k
    return remainder;
831
4.67k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEmlERKS9_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEmlERKS7_
Line
Count
Source
791
45
{
792
    // First we do basic reduction checks of individual elements
793
45
    reduction_check();
794
45
    other.reduction_check();
795
45
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
45
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
45
    bigfield remainder;
799
45
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
45
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
45
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
45
        auto [reduction_required, num_quotient_bits] =
813
45
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
45
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
45
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
45
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
45
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
45
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
45
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
45
    return remainder;
831
45
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEmlERKS7_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEmlERKS9_
Line
Count
Source
791
36
{
792
    // First we do basic reduction checks of individual elements
793
36
    reduction_check();
794
36
    other.reduction_check();
795
36
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
36
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
36
    bigfield remainder;
799
36
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
36
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
36
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
36
        auto [reduction_required, num_quotient_bits] =
813
36
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
36
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
36
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
36
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
36
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
36
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
36
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
36
    return remainder;
831
36
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEmlERKS9_
832
833
/**
834
 * Division operator. Create constraints for b!=0 by default. If you need a variant
835
 *without the zero check,  use div_without_denominator_check.
836
 *
837
 * To evaluate (a / b = c mod p), we instead evaluate (c * b = a mod p).
838
 **/
839
template <typename Builder, typename T>
840
bigfield<Builder, T> bigfield<Builder, T>::operator/(const bigfield& other) const
841
4.20k
{
842
843
4.20k
    return internal_div({ *this }, other, true);
844
4.20k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEdvERKS6_
Line
Count
Source
841
4.17k
{
842
843
4.17k
    return internal_div({ *this }, other, true);
844
4.17k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEdvERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEdvERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EdvERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEdvERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEdvERKS7_
Line
Count
Source
841
12
{
842
843
12
    return internal_div({ *this }, other, true);
844
12
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEdvERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEdvERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEdvERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEdvERKS7_
Line
Count
Source
841
8
{
842
843
8
    return internal_div({ *this }, other, true);
844
8
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEdvERKS9_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEdvERKS9_
Line
Count
Source
841
8
{
842
843
8
    return internal_div({ *this }, other, true);
844
8
}
845
/**
846
 * @brief Create constraints for summing these terms
847
 *
848
 * @tparam Builder
849
 * @tparam T
850
 * @param terms
851
 * @return The sum of terms
852
 */
853
template <typename Builder, typename T>
854
bigfield<Builder, T> bigfield<Builder, T>::sum(const std::vector<bigfield>& terms)
855
0
{
856
0
    ASSERT(terms.size() > 0);
857
858
0
    if (terms.size() == 1) {
859
0
        return terms[0];
860
0
    }
861
862
0
    bigfield acc = terms[0];
863
0
    for (size_t i = 1; i < (terms.size() + 1) / 2; i++) {
864
0
        acc = acc.add_two(terms[2 * i - 1], terms[2 * i]);
865
0
    }
866
0
    if ((terms.size() & 1) == 0) {
867
0
        acc += terms[terms.size() - 1];
868
0
    }
869
0
    return acc;
870
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sumERKSt6vectorIS7_SaIS7_EE
871
872
/**
873
 * Division of a sum with an optional check if divisor is zero. Should not be used outside of class.
874
 *
875
 * @param numerators Vector of numerators
876
 * @param denominator Denominator
877
 * @param check_for_zero If the zero check should be enabled
878
 *
879
 * @return The result of division
880
 * */
881
template <typename Builder, typename T>
882
bigfield<Builder, T> bigfield<Builder, T>::internal_div(const std::vector<bigfield>& numerators,
883
                                                        const bigfield& denominator,
884
                                                        bool check_for_zero)
885
104k
{
886
104k
    if (numerators.size() == 0) {
887
1
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
1
    }
889
890
104k
    denominator.reduction_check();
891
104k
    Builder* ctx = denominator.context;
892
104k
    uint512_t numerator_values(0);
893
104k
    bool numerator_constant = true;
894
104k
    OriginTag tag = denominator.get_origin_tag();
895
145k
    for (const auto& numerator_element : numerators) {
896
145k
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
145k
        numerator_element.reduction_check();
898
145k
        numerator_values += numerator_element.get_value();
899
145k
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
145k
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
145k
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
104k
    const uint1024_t left = uint1024_t(numerator_values);
906
104k
    const uint1024_t right = uint1024_t(denominator.get_value());
907
104k
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
104k
    uint512_t inverse_value(0);
910
104k
    if (right.lo != uint512_t(0)) {
911
104k
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
104k
    }
913
104k
    uint1024_t inverse_1024(inverse_value);
914
104k
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
104k
    const uint1024_t quotient_1024 =
917
104k
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
104k
    const uint512_t quotient_value = quotient_1024.lo;
919
920
104k
    bigfield inverse;
921
104k
    bigfield quotient;
922
104k
    if (numerator_constant && denominator.is_constant()) {
923
65
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
65
        inverse.set_origin_tag(tag);
925
65
        return inverse;
926
104k
    } else {
927
        // We only add the check if the result is non-constant
928
104k
        std::vector<uint1024_t> numerator_max;
929
145k
        for (const auto& n : numerators) {
930
145k
            numerator_max.push_back(n.get_maximum_value());
931
145k
        }
932
933
104k
        auto [reduction_required, num_quotient_bits] =
934
104k
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
104k
                                        { denominator.get_maximum_value() },
936
104k
                                        { unreduced_zero() },
937
104k
                                        numerator_max);
938
104k
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
104k
        if (check_for_zero) {
945
4.13k
            denominator.assert_is_not_equal(zero());
946
4.13k
        }
947
948
104k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
104k
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
104k
    }
951
952
104k
    inverse.set_origin_tag(tag);
953
104k
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
104k
    return inverse;
955
104k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12internal_divERKSt6vectorIS6_SaIS6_EERKS6_b
Line
Count
Source
885
94.0k
{
886
94.0k
    if (numerators.size() == 0) {
887
1
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
1
    }
889
890
94.0k
    denominator.reduction_check();
891
94.0k
    Builder* ctx = denominator.context;
892
94.0k
    uint512_t numerator_values(0);
893
94.0k
    bool numerator_constant = true;
894
94.0k
    OriginTag tag = denominator.get_origin_tag();
895
135k
    for (const auto& numerator_element : numerators) {
896
135k
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
135k
        numerator_element.reduction_check();
898
135k
        numerator_values += numerator_element.get_value();
899
135k
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
135k
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
135k
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
94.0k
    const uint1024_t left = uint1024_t(numerator_values);
906
94.0k
    const uint1024_t right = uint1024_t(denominator.get_value());
907
94.0k
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
94.0k
    uint512_t inverse_value(0);
910
94.0k
    if (right.lo != uint512_t(0)) {
911
94.0k
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
94.0k
    }
913
94.0k
    uint1024_t inverse_1024(inverse_value);
914
94.0k
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
94.0k
    const uint1024_t quotient_1024 =
917
94.0k
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
94.0k
    const uint512_t quotient_value = quotient_1024.lo;
919
920
94.0k
    bigfield inverse;
921
94.0k
    bigfield quotient;
922
94.0k
    if (numerator_constant && denominator.is_constant()) {
923
65
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
65
        inverse.set_origin_tag(tag);
925
65
        return inverse;
926
93.9k
    } else {
927
        // We only add the check if the result is non-constant
928
93.9k
        std::vector<uint1024_t> numerator_max;
929
134k
        for (const auto& n : numerators) {
930
134k
            numerator_max.push_back(n.get_maximum_value());
931
134k
        }
932
933
93.9k
        auto [reduction_required, num_quotient_bits] =
934
93.9k
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
93.9k
                                        { denominator.get_maximum_value() },
936
93.9k
                                        { unreduced_zero() },
937
93.9k
                                        numerator_max);
938
93.9k
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
93.9k
        if (check_for_zero) {
945
4.11k
            denominator.assert_is_not_equal(zero());
946
4.11k
        }
947
948
93.9k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
93.9k
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
93.9k
    }
951
952
93.9k
    inverse.set_origin_tag(tag);
953
93.9k
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
93.9k
    return inverse;
955
94.0k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12internal_divERKSt6vectorIS6_SaIS6_EERKS6_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12internal_divERKSt6vectorIS8_SaIS8_EERKS8_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
488
{
886
488
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
488
    denominator.reduction_check();
891
488
    Builder* ctx = denominator.context;
892
488
    uint512_t numerator_values(0);
893
488
    bool numerator_constant = true;
894
488
    OriginTag tag = denominator.get_origin_tag();
895
494
    for (const auto& numerator_element : numerators) {
896
494
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
494
        numerator_element.reduction_check();
898
494
        numerator_values += numerator_element.get_value();
899
494
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
494
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
494
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
488
    const uint1024_t left = uint1024_t(numerator_values);
906
488
    const uint1024_t right = uint1024_t(denominator.get_value());
907
488
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
488
    uint512_t inverse_value(0);
910
488
    if (right.lo != uint512_t(0)) {
911
488
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
488
    }
913
488
    uint1024_t inverse_1024(inverse_value);
914
488
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
488
    const uint1024_t quotient_1024 =
917
488
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
488
    const uint512_t quotient_value = quotient_1024.lo;
919
920
488
    bigfield inverse;
921
488
    bigfield quotient;
922
488
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
488
    } else {
927
        // We only add the check if the result is non-constant
928
488
        std::vector<uint1024_t> numerator_max;
929
494
        for (const auto& n : numerators) {
930
494
            numerator_max.push_back(n.get_maximum_value());
931
494
        }
932
933
488
        auto [reduction_required, num_quotient_bits] =
934
488
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
488
                                        { denominator.get_maximum_value() },
936
488
                                        { unreduced_zero() },
937
488
                                        numerator_max);
938
488
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
488
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
488
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
488
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
488
    }
951
952
488
    inverse.set_origin_tag(tag);
953
488
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
488
    return inverse;
955
488
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
14
{
886
14
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
14
    denominator.reduction_check();
891
14
    Builder* ctx = denominator.context;
892
14
    uint512_t numerator_values(0);
893
14
    bool numerator_constant = true;
894
14
    OriginTag tag = denominator.get_origin_tag();
895
14
    for (const auto& numerator_element : numerators) {
896
14
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
14
        numerator_element.reduction_check();
898
14
        numerator_values += numerator_element.get_value();
899
14
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
14
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
14
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
14
    const uint1024_t left = uint1024_t(numerator_values);
906
14
    const uint1024_t right = uint1024_t(denominator.get_value());
907
14
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
14
    uint512_t inverse_value(0);
910
14
    if (right.lo != uint512_t(0)) {
911
14
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
14
    }
913
14
    uint1024_t inverse_1024(inverse_value);
914
14
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
14
    const uint1024_t quotient_1024 =
917
14
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
14
    const uint512_t quotient_value = quotient_1024.lo;
919
920
14
    bigfield inverse;
921
14
    bigfield quotient;
922
14
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
14
    } else {
927
        // We only add the check if the result is non-constant
928
14
        std::vector<uint1024_t> numerator_max;
929
14
        for (const auto& n : numerators) {
930
14
            numerator_max.push_back(n.get_maximum_value());
931
14
        }
932
933
14
        auto [reduction_required, num_quotient_bits] =
934
14
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
14
                                        { denominator.get_maximum_value() },
936
14
                                        { unreduced_zero() },
937
14
                                        numerator_max);
938
14
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
14
        if (check_for_zero) {
945
12
            denominator.assert_is_not_equal(zero());
946
12
        }
947
948
14
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
14
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
14
    }
951
952
14
    inverse.set_origin_tag(tag);
953
14
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
14
    return inverse;
955
14
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Line
Count
Source
885
8.66k
{
886
8.66k
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
8.66k
    denominator.reduction_check();
891
8.66k
    Builder* ctx = denominator.context;
892
8.66k
    uint512_t numerator_values(0);
893
8.66k
    bool numerator_constant = true;
894
8.66k
    OriginTag tag = denominator.get_origin_tag();
895
8.77k
    for (const auto& numerator_element : numerators) {
896
8.77k
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
8.77k
        numerator_element.reduction_check();
898
8.77k
        numerator_values += numerator_element.get_value();
899
8.77k
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
8.77k
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
8.77k
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
8.66k
    const uint1024_t left = uint1024_t(numerator_values);
906
8.66k
    const uint1024_t right = uint1024_t(denominator.get_value());
907
8.66k
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
8.66k
    uint512_t inverse_value(0);
910
8.66k
    if (right.lo != uint512_t(0)) {
911
8.66k
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
8.66k
    }
913
8.66k
    uint1024_t inverse_1024(inverse_value);
914
8.66k
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
8.66k
    const uint1024_t quotient_1024 =
917
8.66k
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
8.66k
    const uint512_t quotient_value = quotient_1024.lo;
919
920
8.66k
    bigfield inverse;
921
8.66k
    bigfield quotient;
922
8.66k
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
8.66k
    } else {
927
        // We only add the check if the result is non-constant
928
8.66k
        std::vector<uint1024_t> numerator_max;
929
8.77k
        for (const auto& n : numerators) {
930
8.77k
            numerator_max.push_back(n.get_maximum_value());
931
8.77k
        }
932
933
8.66k
        auto [reduction_required, num_quotient_bits] =
934
8.66k
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
8.66k
                                        { denominator.get_maximum_value() },
936
8.66k
                                        { unreduced_zero() },
937
8.66k
                                        numerator_max);
938
8.66k
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
8.66k
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
8.66k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
8.66k
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
8.66k
    }
951
952
8.66k
    inverse.set_origin_tag(tag);
953
8.66k
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
8.66k
    return inverse;
955
8.66k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Line
Count
Source
885
228
{
886
228
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
228
    denominator.reduction_check();
891
228
    Builder* ctx = denominator.context;
892
228
    uint512_t numerator_values(0);
893
228
    bool numerator_constant = true;
894
228
    OriginTag tag = denominator.get_origin_tag();
895
228
    for (const auto& numerator_element : numerators) {
896
228
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
228
        numerator_element.reduction_check();
898
228
        numerator_values += numerator_element.get_value();
899
228
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
228
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
228
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
228
    const uint1024_t left = uint1024_t(numerator_values);
906
228
    const uint1024_t right = uint1024_t(denominator.get_value());
907
228
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
228
    uint512_t inverse_value(0);
910
228
    if (right.lo != uint512_t(0)) {
911
228
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
228
    }
913
228
    uint1024_t inverse_1024(inverse_value);
914
228
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
228
    const uint1024_t quotient_1024 =
917
228
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
228
    const uint512_t quotient_value = quotient_1024.lo;
919
920
228
    bigfield inverse;
921
228
    bigfield quotient;
922
228
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
228
    } else {
927
        // We only add the check if the result is non-constant
928
228
        std::vector<uint1024_t> numerator_max;
929
228
        for (const auto& n : numerators) {
930
228
            numerator_max.push_back(n.get_maximum_value());
931
228
        }
932
933
228
        auto [reduction_required, num_quotient_bits] =
934
228
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
228
                                        { denominator.get_maximum_value() },
936
228
                                        { unreduced_zero() },
937
228
                                        numerator_max);
938
228
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
228
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
228
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
228
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
228
    }
951
952
228
    inverse.set_origin_tag(tag);
953
228
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
228
    return inverse;
955
228
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
670
{
886
670
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
670
    denominator.reduction_check();
891
670
    Builder* ctx = denominator.context;
892
670
    uint512_t numerator_values(0);
893
670
    bool numerator_constant = true;
894
670
    OriginTag tag = denominator.get_origin_tag();
895
685
    for (const auto& numerator_element : numerators) {
896
685
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
685
        numerator_element.reduction_check();
898
685
        numerator_values += numerator_element.get_value();
899
685
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
685
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
685
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
670
    const uint1024_t left = uint1024_t(numerator_values);
906
670
    const uint1024_t right = uint1024_t(denominator.get_value());
907
670
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
670
    uint512_t inverse_value(0);
910
670
    if (right.lo != uint512_t(0)) {
911
670
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
670
    }
913
670
    uint1024_t inverse_1024(inverse_value);
914
670
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
670
    const uint1024_t quotient_1024 =
917
670
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
670
    const uint512_t quotient_value = quotient_1024.lo;
919
920
670
    bigfield inverse;
921
670
    bigfield quotient;
922
670
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
670
    } else {
927
        // We only add the check if the result is non-constant
928
670
        std::vector<uint1024_t> numerator_max;
929
685
        for (const auto& n : numerators) {
930
685
            numerator_max.push_back(n.get_maximum_value());
931
685
        }
932
933
670
        auto [reduction_required, num_quotient_bits] =
934
670
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
670
                                        { denominator.get_maximum_value() },
936
670
                                        { unreduced_zero() },
937
670
                                        numerator_max);
938
670
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
670
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
670
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
670
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
670
    }
951
952
670
    inverse.set_origin_tag(tag);
953
670
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
670
    return inverse;
955
670
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
10
{
886
10
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
10
    denominator.reduction_check();
891
10
    Builder* ctx = denominator.context;
892
10
    uint512_t numerator_values(0);
893
10
    bool numerator_constant = true;
894
10
    OriginTag tag = denominator.get_origin_tag();
895
10
    for (const auto& numerator_element : numerators) {
896
10
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
10
        numerator_element.reduction_check();
898
10
        numerator_values += numerator_element.get_value();
899
10
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
10
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
10
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
10
    const uint1024_t left = uint1024_t(numerator_values);
906
10
    const uint1024_t right = uint1024_t(denominator.get_value());
907
10
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
10
    uint512_t inverse_value(0);
910
10
    if (right.lo != uint512_t(0)) {
911
10
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
10
    }
913
10
    uint1024_t inverse_1024(inverse_value);
914
10
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
10
    const uint1024_t quotient_1024 =
917
10
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
10
    const uint512_t quotient_value = quotient_1024.lo;
919
920
10
    bigfield inverse;
921
10
    bigfield quotient;
922
10
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
10
    } else {
927
        // We only add the check if the result is non-constant
928
10
        std::vector<uint1024_t> numerator_max;
929
10
        for (const auto& n : numerators) {
930
10
            numerator_max.push_back(n.get_maximum_value());
931
10
        }
932
933
10
        auto [reduction_required, num_quotient_bits] =
934
10
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
10
                                        { denominator.get_maximum_value() },
936
10
                                        { unreduced_zero() },
937
10
                                        numerator_max);
938
10
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
10
        if (check_for_zero) {
945
8
            denominator.assert_is_not_equal(zero());
946
8
        }
947
948
10
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
10
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
10
    }
951
952
10
    inverse.set_origin_tag(tag);
953
10
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
10
    return inverse;
955
10
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Line
Count
Source
885
536
{
886
536
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
536
    denominator.reduction_check();
891
536
    Builder* ctx = denominator.context;
892
536
    uint512_t numerator_values(0);
893
536
    bool numerator_constant = true;
894
536
    OriginTag tag = denominator.get_origin_tag();
895
548
    for (const auto& numerator_element : numerators) {
896
548
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
548
        numerator_element.reduction_check();
898
548
        numerator_values += numerator_element.get_value();
899
548
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
548
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
548
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
536
    const uint1024_t left = uint1024_t(numerator_values);
906
536
    const uint1024_t right = uint1024_t(denominator.get_value());
907
536
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
536
    uint512_t inverse_value(0);
910
536
    if (right.lo != uint512_t(0)) {
911
536
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
536
    }
913
536
    uint1024_t inverse_1024(inverse_value);
914
536
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
536
    const uint1024_t quotient_1024 =
917
536
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
536
    const uint512_t quotient_value = quotient_1024.lo;
919
920
536
    bigfield inverse;
921
536
    bigfield quotient;
922
536
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
536
    } else {
927
        // We only add the check if the result is non-constant
928
536
        std::vector<uint1024_t> numerator_max;
929
548
        for (const auto& n : numerators) {
930
548
            numerator_max.push_back(n.get_maximum_value());
931
548
        }
932
933
536
        auto [reduction_required, num_quotient_bits] =
934
536
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
536
                                        { denominator.get_maximum_value() },
936
536
                                        { unreduced_zero() },
937
536
                                        numerator_max);
938
536
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
536
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
536
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
536
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
536
    }
951
952
536
    inverse.set_origin_tag(tag);
953
536
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
536
    return inverse;
955
536
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Line
Count
Source
885
8
{
886
8
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
8
    denominator.reduction_check();
891
8
    Builder* ctx = denominator.context;
892
8
    uint512_t numerator_values(0);
893
8
    bool numerator_constant = true;
894
8
    OriginTag tag = denominator.get_origin_tag();
895
8
    for (const auto& numerator_element : numerators) {
896
8
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
8
        numerator_element.reduction_check();
898
8
        numerator_values += numerator_element.get_value();
899
8
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
8
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
8
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
8
    const uint1024_t left = uint1024_t(numerator_values);
906
8
    const uint1024_t right = uint1024_t(denominator.get_value());
907
8
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
8
    uint512_t inverse_value(0);
910
8
    if (right.lo != uint512_t(0)) {
911
8
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
8
    }
913
8
    uint1024_t inverse_1024(inverse_value);
914
8
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
8
    const uint1024_t quotient_1024 =
917
8
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
8
    const uint512_t quotient_value = quotient_1024.lo;
919
920
8
    bigfield inverse;
921
8
    bigfield quotient;
922
8
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
8
    } else {
927
        // We only add the check if the result is non-constant
928
8
        std::vector<uint1024_t> numerator_max;
929
8
        for (const auto& n : numerators) {
930
8
            numerator_max.push_back(n.get_maximum_value());
931
8
        }
932
933
8
        auto [reduction_required, num_quotient_bits] =
934
8
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
8
                                        { denominator.get_maximum_value() },
936
8
                                        { unreduced_zero() },
937
8
                                        numerator_max);
938
8
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
8
        if (check_for_zero) {
945
8
            denominator.assert_is_not_equal(zero());
946
8
        }
947
948
8
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
8
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
8
    }
951
952
8
    inverse.set_origin_tag(tag);
953
8
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
8
    return inverse;
955
8
}
956
957
/**
958
 * Div method without constraining denominator!=0.
959
 *
960
 * Similar to operator/ but numerator can be linear sum of multiple elements
961
 *
962
 **/
963
template <typename Builder, typename T>
964
bigfield<Builder, T> bigfield<Builder, T>::div_without_denominator_check(const std::vector<bigfield>& numerators,
965
                                                                         const bigfield& denominator)
966
100k
{
967
100k
    return internal_div(numerators, denominator, false);
968
100k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKSt6vectorIS6_SaIS6_EERKS6_
Line
Count
Source
966
89.8k
{
967
89.8k
    return internal_div(numerators, denominator, false);
968
89.8k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_without_denominator_checkERKSt6vectorIS6_SaIS6_EERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKSt6vectorIS8_SaIS8_EERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
Line
Count
Source
966
488
{
967
488
    return internal_div(numerators, denominator, false);
968
488
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
Line
Count
Source
966
8.66k
{
967
8.66k
    return internal_div(numerators, denominator, false);
968
8.66k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
Line
Count
Source
966
670
{
967
670
    return internal_div(numerators, denominator, false);
968
670
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
Line
Count
Source
966
536
{
967
536
    return internal_div(numerators, denominator, false);
968
536
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
969
970
template <typename Builder, typename T>
971
bigfield<Builder, T> bigfield<Builder, T>::div_without_denominator_check(const bigfield& denominator)
972
232
{
973
232
    return internal_div({ *this }, denominator, false);
974
232
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_without_denominator_checkERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_without_denominator_checkERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKS7_
Line
Count
Source
972
2
{
973
2
    return internal_div({ *this }, denominator, false);
974
2
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKS9_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKS9_
Line
Count
Source
972
228
{
973
228
    return internal_div({ *this }, denominator, false);
974
228
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKS7_
Line
Count
Source
972
2
{
973
2
    return internal_div({ *this }, denominator, false);
974
2
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKS9_
975
976
/**
977
 * Div method with constraints for denominator!=0.
978
 *
979
 * Similar to operator/ but numerator can be linear sum of multiple elements
980
 *
981
 * TODO: After we create a mechanism for easy updating of witnesses, create a test with proof check
982
 **/
983
template <typename Builder, typename T>
984
bigfield<Builder, T> bigfield<Builder, T>::div_check_denominator_nonzero(const std::vector<bigfield>& numerators,
985
                                                                         const bigfield& denominator)
986
1
{
987
1
    return internal_div(numerators, denominator, true);
988
1
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS6_SaIS6_EERKS6_
Line
Count
Source
986
1
{
987
1
    return internal_div(numerators, denominator, true);
988
1
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS6_SaIS6_EERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS8_SaIS8_EERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
989
/**
990
 * Compute a * a = c mod p
991
 *
992
 * Slightly cheaper than operator* for Standard
993
 **/
994
template <typename Builder, typename T> bigfield<Builder, T> bigfield<Builder, T>::sqr() const
995
3.07k
{
996
3.07k
    reduction_check();
997
3.07k
    Builder* ctx = context;
998
999
3.07k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
3.07k
    bigfield remainder;
1002
3.07k
    bigfield quotient;
1003
3.07k
    if (is_constant()) {
1004
208
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
208
        return remainder;
1006
2.86k
    } else {
1007
1008
2.86k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
2.86k
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
2.86k
        if (reduction_required) {
1011
1
            self_reduce();
1012
1
            return sqr();
1013
1
        }
1014
1015
2.86k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
2.86k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
2.86k
    };
1018
1019
2.86k
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
2.86k
    remainder.set_origin_tag(get_origin_tag());
1021
2.86k
    return remainder;
1022
3.07k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sqrEv
Line
Count
Source
995
2.82k
{
996
2.82k
    reduction_check();
997
2.82k
    Builder* ctx = context;
998
999
2.82k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
2.82k
    bigfield remainder;
1002
2.82k
    bigfield quotient;
1003
2.82k
    if (is_constant()) {
1004
208
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
208
        return remainder;
1006
2.62k
    } else {
1007
1008
2.62k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
2.62k
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
2.62k
        if (reduction_required) {
1011
1
            self_reduce();
1012
1
            return sqr();
1013
1
        }
1014
1015
2.62k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
2.62k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
2.62k
    };
1018
1019
2.62k
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
2.62k
    remainder.set_origin_tag(get_origin_tag());
1021
2.62k
    return remainder;
1022
2.82k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sqrEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sqrEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sqrEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3sqrEv
Line
Count
Source
995
9
{
996
9
    reduction_check();
997
9
    Builder* ctx = context;
998
999
9
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
9
    bigfield remainder;
1002
9
    bigfield quotient;
1003
9
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
9
    } else {
1007
1008
9
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
9
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
9
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
9
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
9
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
9
    };
1018
1019
9
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
9
    remainder.set_origin_tag(get_origin_tag());
1021
9
    return remainder;
1022
9
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3sqrEv
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3sqrEv
Line
Count
Source
995
228
{
996
228
    reduction_check();
997
228
    Builder* ctx = context;
998
999
228
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
228
    bigfield remainder;
1002
228
    bigfield quotient;
1003
228
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
228
    } else {
1007
1008
228
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
228
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
228
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
228
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
228
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
228
    };
1018
1019
228
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
228
    remainder.set_origin_tag(get_origin_tag());
1021
228
    return remainder;
1022
228
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3sqrEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3sqrEv
Line
Count
Source
995
6
{
996
6
    reduction_check();
997
6
    Builder* ctx = context;
998
999
6
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
6
    bigfield remainder;
1002
6
    bigfield quotient;
1003
6
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
6
    } else {
1007
1008
6
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
6
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
6
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
6
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
6
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
6
    };
1018
1019
6
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
6
    remainder.set_origin_tag(get_origin_tag());
1021
6
    return remainder;
1022
6
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3sqrEv
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3sqrEv
Line
Count
Source
995
4
{
996
4
    reduction_check();
997
4
    Builder* ctx = context;
998
999
4
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
4
    bigfield remainder;
1002
4
    bigfield quotient;
1003
4
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
4
    } else {
1007
1008
4
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
4
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
4
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
4
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
4
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
4
    };
1018
1019
4
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
4
    remainder.set_origin_tag(get_origin_tag());
1021
4
    return remainder;
1022
4
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3sqrEv
1023
1024
/**
1025
 * Compute a * a + ...to_add = b mod p
1026
 *
1027
 * We can chain multiple additions to a square/multiply with a single quotient/remainder.
1028
 *
1029
 * Chaining the additions here is cheaper than calling operator+ because we can combine some gates in
1030
 *`evaluate_multiply_add`
1031
 **/
1032
template <typename Builder, typename T>
1033
bigfield<Builder, T> bigfield<Builder, T>::sqradd(const std::vector<bigfield>& to_add) const
1034
328k
{
1035
328k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
0
    reduction_check();
1037
1038
0
    Builder* ctx = context;
1039
1040
0
    uint512_t add_values(0);
1041
0
    bool add_constant = true;
1042
629k
    for (const auto& add_element : to_add) {
1043
629k
        add_element.reduction_check();
1044
629k
        add_values += add_element.get_value();
1045
629k
        add_constant = add_constant && (add_element.is_constant());
1046
629k
    }
1047
1048
0
    const uint1024_t left(get_value());
1049
0
    const uint1024_t right(get_value());
1050
0
    const uint1024_t add_right(add_values);
1051
0
    const uint1024_t modulus(target_basis.modulus);
1052
1053
0
    bigfield remainder;
1054
0
    bigfield quotient;
1055
328k
    if (is_constant()) {
1056
2
        if (add_constant) {
1057
1058
2
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
2
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
2
            OriginTag new_tag = get_origin_tag();
1062
2
            for (auto& element : to_add) {
1063
2
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
2
            }
1065
2
            remainder.set_origin_tag(new_tag);
1066
2
            return remainder;
1067
2
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
328k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
328k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
328k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
328k
        if (reduction_required) {
1085
1
            self_reduce();
1086
1
            return sqradd(to_add);
1087
1
        }
1088
328k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
328k
        uint512_t quotient_value = quotient_1024.lo;
1090
328k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
328k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
328k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
328k
    };
1095
328k
    OriginTag new_tag = get_origin_tag();
1096
629k
    for (auto& element : to_add) {
1097
629k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
629k
    }
1099
328k
    remainder.set_origin_tag(new_tag);
1100
328k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
328k
    return remainder;
1102
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Line
Count
Source
1034
308k
{
1035
308k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
308k
    reduction_check();
1037
1038
308k
    Builder* ctx = context;
1039
1040
308k
    uint512_t add_values(0);
1041
308k
    bool add_constant = true;
1042
594k
    for (const auto& add_element : to_add) {
1043
594k
        add_element.reduction_check();
1044
594k
        add_values += add_element.get_value();
1045
594k
        add_constant = add_constant && (add_element.is_constant());
1046
594k
    }
1047
1048
308k
    const uint1024_t left(get_value());
1049
308k
    const uint1024_t right(get_value());
1050
308k
    const uint1024_t add_right(add_values);
1051
308k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
308k
    bigfield remainder;
1054
308k
    bigfield quotient;
1055
308k
    if (is_constant()) {
1056
2
        if (add_constant) {
1057
1058
2
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
2
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
2
            OriginTag new_tag = get_origin_tag();
1062
2
            for (auto& element : to_add) {
1063
2
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
2
            }
1065
2
            remainder.set_origin_tag(new_tag);
1066
2
            return remainder;
1067
2
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
308k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
308k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
308k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
308k
        if (reduction_required) {
1085
1
            self_reduce();
1086
1
            return sqradd(to_add);
1087
1
        }
1088
308k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
308k
        uint512_t quotient_value = quotient_1024.lo;
1090
308k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
308k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
308k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
308k
    };
1095
308k
    OriginTag new_tag = get_origin_tag();
1096
594k
    for (auto& element : to_add) {
1097
594k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
594k
    }
1099
308k
    remainder.set_origin_tag(new_tag);
1100
308k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
308k
    return remainder;
1102
308k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E6sqraddERKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1034
1.00k
{
1035
1.00k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
1.00k
    reduction_check();
1037
1038
1.00k
    Builder* ctx = context;
1039
1040
1.00k
    uint512_t add_values(0);
1041
1.00k
    bool add_constant = true;
1042
1.69k
    for (const auto& add_element : to_add) {
1043
1.69k
        add_element.reduction_check();
1044
1.69k
        add_values += add_element.get_value();
1045
1.69k
        add_constant = add_constant && (add_element.is_constant());
1046
1.69k
    }
1047
1048
1.00k
    const uint1024_t left(get_value());
1049
1.00k
    const uint1024_t right(get_value());
1050
1.00k
    const uint1024_t add_right(add_values);
1051
1.00k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
1.00k
    bigfield remainder;
1054
1.00k
    bigfield quotient;
1055
1.00k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
1.00k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
1.00k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
1.00k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
1.00k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
1.00k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
1.00k
        uint512_t quotient_value = quotient_1024.lo;
1090
1.00k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
1.00k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
1.00k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
1.00k
    };
1095
1.00k
    OriginTag new_tag = get_origin_tag();
1096
1.69k
    for (auto& element : to_add) {
1097
1.69k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
1.69k
    }
1099
1.00k
    remainder.set_origin_tag(new_tag);
1100
1.00k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
1.00k
    return remainder;
1102
1.00k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1034
16.3k
{
1035
16.3k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
16.3k
    reduction_check();
1037
1038
16.3k
    Builder* ctx = context;
1039
1040
16.3k
    uint512_t add_values(0);
1041
16.3k
    bool add_constant = true;
1042
28.8k
    for (const auto& add_element : to_add) {
1043
28.8k
        add_element.reduction_check();
1044
28.8k
        add_values += add_element.get_value();
1045
28.8k
        add_constant = add_constant && (add_element.is_constant());
1046
28.8k
    }
1047
1048
16.3k
    const uint1024_t left(get_value());
1049
16.3k
    const uint1024_t right(get_value());
1050
16.3k
    const uint1024_t add_right(add_values);
1051
16.3k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
16.3k
    bigfield remainder;
1054
16.3k
    bigfield quotient;
1055
16.3k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
16.3k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
16.3k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
16.3k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
16.3k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
16.3k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
16.3k
        uint512_t quotient_value = quotient_1024.lo;
1090
16.3k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
16.3k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
16.3k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
16.3k
    };
1095
16.3k
    OriginTag new_tag = get_origin_tag();
1096
28.8k
    for (auto& element : to_add) {
1097
28.8k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
28.8k
    }
1099
16.3k
    remainder.set_origin_tag(new_tag);
1100
16.3k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
16.3k
    return remainder;
1102
16.3k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1034
1.30k
{
1035
1.30k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
1.30k
    reduction_check();
1037
1038
1.30k
    Builder* ctx = context;
1039
1040
1.30k
    uint512_t add_values(0);
1041
1.30k
    bool add_constant = true;
1042
2.60k
    for (const auto& add_element : to_add) {
1043
2.60k
        add_element.reduction_check();
1044
2.60k
        add_values += add_element.get_value();
1045
2.60k
        add_constant = add_constant && (add_element.is_constant());
1046
2.60k
    }
1047
1048
1.30k
    const uint1024_t left(get_value());
1049
1.30k
    const uint1024_t right(get_value());
1050
1.30k
    const uint1024_t add_right(add_values);
1051
1.30k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
1.30k
    bigfield remainder;
1054
1.30k
    bigfield quotient;
1055
1.30k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
1.30k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
1.30k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
1.30k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
1.30k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
1.30k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
1.30k
        uint512_t quotient_value = quotient_1024.lo;
1090
1.30k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
1.30k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
1.30k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
1.30k
    };
1095
1.30k
    OriginTag new_tag = get_origin_tag();
1096
2.60k
    for (auto& element : to_add) {
1097
2.60k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
2.60k
    }
1099
1.30k
    remainder.set_origin_tag(new_tag);
1100
1.30k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
1.30k
    return remainder;
1102
1.30k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1034
1.04k
{
1035
1.04k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
1.04k
    reduction_check();
1037
1038
1.04k
    Builder* ctx = context;
1039
1040
1.04k
    uint512_t add_values(0);
1041
1.04k
    bool add_constant = true;
1042
2.08k
    for (const auto& add_element : to_add) {
1043
2.08k
        add_element.reduction_check();
1044
2.08k
        add_values += add_element.get_value();
1045
2.08k
        add_constant = add_constant && (add_element.is_constant());
1046
2.08k
    }
1047
1048
1.04k
    const uint1024_t left(get_value());
1049
1.04k
    const uint1024_t right(get_value());
1050
1.04k
    const uint1024_t add_right(add_values);
1051
1.04k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
1.04k
    bigfield remainder;
1054
1.04k
    bigfield quotient;
1055
1.04k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
1.04k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
1.04k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
1.04k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
1.04k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
1.04k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
1.04k
        uint512_t quotient_value = quotient_1024.lo;
1090
1.04k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
1.04k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
1.04k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
1.04k
    };
1095
1.04k
    OriginTag new_tag = get_origin_tag();
1096
2.08k
    for (auto& element : to_add) {
1097
2.08k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
2.08k
    }
1099
1.04k
    remainder.set_origin_tag(new_tag);
1100
1.04k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
1.04k
    return remainder;
1102
1.04k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E6sqraddERKSt6vectorIS7_SaIS7_EE
1103
1104
/**
1105
 * @brief Raise a bigfield to a power of an exponent. Note that the exponent must not exceed 32 bits and is
1106
 * implicitly range constrained.
1107
 *
1108
 * @returns this ** (exponent)
1109
 *
1110
 * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/1014) Improve the efficiency of this function.
1111
 */
1112
1113
template <typename Builder, typename T> bigfield<Builder, T> bigfield<Builder, T>::pow(const size_t exponent) const
1114
50
{
1115
    // Just return one immediately
1116
1117
50
    if (exponent == 0) {
1118
0
        return bigfield(uint256_t(1));
1119
0
    }
1120
1121
50
    bool accumulator_initialized = false;
1122
50
    bigfield accumulator;
1123
50
    bigfield running_power = *this;
1124
50
    auto shifted_exponent = exponent;
1125
1126
    // Square and multiply
1127
614
    while (shifted_exponent != 0) {
1128
564
        if (shifted_exponent & 1) {
1129
348
            if (!accumulator_initialized) {
1130
50
                accumulator = running_power;
1131
50
                accumulator_initialized = true;
1132
298
            } else {
1133
298
                accumulator *= running_power;
1134
298
            }
1135
348
        }
1136
564
        if (shifted_exponent != 0) {
1137
564
            running_power = running_power.sqr();
1138
564
        }
1139
564
        shifted_exponent >>= 1;
1140
564
    }
1141
50
    return accumulator;
1142
50
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powEm
Line
Count
Source
1114
50
{
1115
    // Just return one immediately
1116
1117
50
    if (exponent == 0) {
1118
0
        return bigfield(uint256_t(1));
1119
0
    }
1120
1121
50
    bool accumulator_initialized = false;
1122
50
    bigfield accumulator;
1123
50
    bigfield running_power = *this;
1124
50
    auto shifted_exponent = exponent;
1125
1126
    // Square and multiply
1127
614
    while (shifted_exponent != 0) {
1128
564
        if (shifted_exponent & 1) {
1129
348
            if (!accumulator_initialized) {
1130
50
                accumulator = running_power;
1131
50
                accumulator_initialized = true;
1132
298
            } else {
1133
298
                accumulator *= running_power;
1134
298
            }
1135
348
        }
1136
564
        if (shifted_exponent != 0) {
1137
564
            running_power = running_power.sqr();
1138
564
        }
1139
564
        shifted_exponent >>= 1;
1140
564
    }
1141
50
    return accumulator;
1142
50
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3powEm
1143
1144
/**
1145
 * @brief Raise a bigfield to a power of an exponent (field_t) that must be a witness. Note that the exponent must
1146
 * not exceed 32 bits and is implicitly range constrained.
1147
 *
1148
 * @returns this ** (exponent)
1149
 *
1150
 * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/1014) Improve the efficiency of this function.
1151
 */
1152
template <typename Builder, typename T>
1153
bigfield<Builder, T> bigfield<Builder, T>::pow(const field_t<Builder>& exponent) const
1154
20
{
1155
20
    auto* ctx = get_context() ? get_context() : exponent.get_context();
1156
20
    uint256_t exponent_value = exponent.get_value();
1157
1158
20
    ASSERT(exponent_value.get_msb() < 32);
1159
    // Use the constant version that perfoms only the necessary multiplications if the exponent is constant
1160
20
    if (exponent.is_constant()) {
1161
0
        return this->pow(static_cast<uint32_t>(exponent_value));
1162
0
    }
1163
20
    std::vector<bool_t<Builder>> exponent_bits(32);
1164
    // Collect individual bits as bool_t's
1165
660
    for (size_t i = 0; i < exponent_bits.size(); ++i) {
1166
640
        uint256_t value_bit = exponent_value & 1;
1167
640
        bool_t<Builder> bit;
1168
640
        bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0]));
1169
640
        exponent_bits[31 - i] = (bit);
1170
640
        exponent_value >>= 1;
1171
640
    }
1172
1173
20
    field_t<Builder> exponent_accumulator(ctx, 0);
1174
1175
    // Reconstruct the exponent from bits
1176
640
    for (const auto& bit : exponent_bits) {
1177
640
        exponent_accumulator += exponent_accumulator;
1178
640
        exponent_accumulator += field_t<Builder>(bit);
1179
640
    }
1180
1181
    // Ensure it's equal to the original
1182
20
    exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect");
1183
20
    bigfield accumulator(ctx, 1);
1184
20
    bigfield one(1);
1185
    // Compute the power with a square-and-multiply algorithm
1186
660
    for (size_t digit_idx = 0; digit_idx < 32; ++digit_idx) {
1187
640
        accumulator *= accumulator;
1188
640
        accumulator *= one.conditional_select(*this, exponent_bits[digit_idx]);
1189
640
    }
1190
20
    accumulator.self_reduce();
1191
20
    accumulator.set_origin_tag(OriginTag(get_origin_tag(), exponent.tag));
1192
20
    return accumulator;
1193
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS4_EE
Line
Count
Source
1154
20
{
1155
20
    auto* ctx = get_context() ? get_context() : exponent.get_context();
1156
20
    uint256_t exponent_value = exponent.get_value();
1157
1158
20
    ASSERT(exponent_value.get_msb() < 32);
1159
    // Use the constant version that perfoms only the necessary multiplications if the exponent is constant
1160
20
    if (exponent.is_constant()) {
1161
0
        return this->pow(static_cast<uint32_t>(exponent_value));
1162
0
    }
1163
20
    std::vector<bool_t<Builder>> exponent_bits(32);
1164
    // Collect individual bits as bool_t's
1165
660
    for (size_t i = 0; i < exponent_bits.size(); ++i) {
1166
640
        uint256_t value_bit = exponent_value & 1;
1167
640
        bool_t<Builder> bit;
1168
640
        bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0]));
1169
640
        exponent_bits[31 - i] = (bit);
1170
640
        exponent_value >>= 1;
1171
640
    }
1172
1173
20
    field_t<Builder> exponent_accumulator(ctx, 0);
1174
1175
    // Reconstruct the exponent from bits
1176
640
    for (const auto& bit : exponent_bits) {
1177
640
        exponent_accumulator += exponent_accumulator;
1178
640
        exponent_accumulator += field_t<Builder>(bit);
1179
640
    }
1180
1181
    // Ensure it's equal to the original
1182
20
    exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect");
1183
20
    bigfield accumulator(ctx, 1);
1184
20
    bigfield one(1);
1185
    // Compute the power with a square-and-multiply algorithm
1186
660
    for (size_t digit_idx = 0; digit_idx < 32; ++digit_idx) {
1187
640
        accumulator *= accumulator;
1188
640
        accumulator *= one.conditional_select(*this, exponent_bits[digit_idx]);
1189
640
    }
1190
20
    accumulator.self_reduce();
1191
20
    accumulator.set_origin_tag(OriginTag(get_origin_tag(), exponent.tag));
1192
20
    return accumulator;
1193
20
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powERKNS0_7field_tIS6_EE
1194
1195
/**
1196
 * Compute a * b + ...to_add = c mod p
1197
 *
1198
 * @param to_mul Bigfield element to multiply by
1199
 * @param to_add Vector of elements to add
1200
 *
1201
 * @return New bigfield elment c
1202
 **/
1203
template <typename Builder, typename T>
1204
bigfield<Builder, T> bigfield<Builder, T>::madd(const bigfield& to_mul, const std::vector<bigfield>& to_add) const
1205
107k
{
1206
107k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
107k
    Builder* ctx = context ? context : to_mul.context;
1208
0
    reduction_check();
1209
0
    to_mul.reduction_check();
1210
1211
0
    uint512_t add_values(0);
1212
0
    bool add_constant = true;
1213
1214
175k
    for (const auto& add_element : to_add) {
1215
175k
        add_element.reduction_check();
1216
175k
        add_values += add_element.get_value();
1217
175k
        add_constant = add_constant && (add_element.is_constant());
1218
175k
    }
1219
1220
0
    const uint1024_t left(get_value());
1221
0
    const uint1024_t mul_right(to_mul.get_value());
1222
0
    const uint1024_t add_right(add_values);
1223
0
    const uint1024_t modulus(target_basis.modulus);
1224
1225
0
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
0
    const uint512_t quotient_value = quotient_1024.lo;
1228
0
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
0
    bigfield remainder;
1231
0
    bigfield quotient;
1232
107k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
2
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
2
        return remainder;
1235
107k
    } else {
1236
1237
107k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
107k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
107k
        if (reduction_required) {
1240
1
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
1
            } else {
1243
1
                to_mul.self_reduce();
1244
1
            }
1245
1
            return (*this).madd(to_mul, to_add);
1246
1
        }
1247
107k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
107k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
107k
    };
1250
107k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
107k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
175k
    for (auto& element : to_add) {
1253
175k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
175k
    }
1255
107k
    return remainder;
1256
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
1205
87.8k
{
1206
87.8k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
87.8k
    Builder* ctx = context ? context : to_mul.context;
1208
87.8k
    reduction_check();
1209
87.8k
    to_mul.reduction_check();
1210
1211
87.8k
    uint512_t add_values(0);
1212
87.8k
    bool add_constant = true;
1213
1214
141k
    for (const auto& add_element : to_add) {
1215
141k
        add_element.reduction_check();
1216
141k
        add_values += add_element.get_value();
1217
141k
        add_constant = add_constant && (add_element.is_constant());
1218
141k
    }
1219
1220
87.8k
    const uint1024_t left(get_value());
1221
87.8k
    const uint1024_t mul_right(to_mul.get_value());
1222
87.8k
    const uint1024_t add_right(add_values);
1223
87.8k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
87.8k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
87.8k
    const uint512_t quotient_value = quotient_1024.lo;
1228
87.8k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
87.8k
    bigfield remainder;
1231
87.8k
    bigfield quotient;
1232
87.8k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
2
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
2
        return remainder;
1235
87.8k
    } else {
1236
1237
87.8k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
87.8k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
87.8k
        if (reduction_required) {
1240
1
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
1
            } else {
1243
1
                to_mul.self_reduce();
1244
1
            }
1245
1
            return (*this).madd(to_mul, to_add);
1246
1
        }
1247
87.8k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
87.8k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
87.8k
    };
1250
87.8k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
87.8k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
141k
    for (auto& element : to_add) {
1253
141k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
141k
    }
1255
87.8k
    return remainder;
1256
87.8k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE4maddERKS8_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E4maddERKS7_RKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1205
974
{
1206
974
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
974
    Builder* ctx = context ? context : to_mul.context;
1208
974
    reduction_check();
1209
974
    to_mul.reduction_check();
1210
1211
974
    uint512_t add_values(0);
1212
974
    bool add_constant = true;
1213
1214
1.55k
    for (const auto& add_element : to_add) {
1215
1.55k
        add_element.reduction_check();
1216
1.55k
        add_values += add_element.get_value();
1217
1.55k
        add_constant = add_constant && (add_element.is_constant());
1218
1.55k
    }
1219
1220
974
    const uint1024_t left(get_value());
1221
974
    const uint1024_t mul_right(to_mul.get_value());
1222
974
    const uint1024_t add_right(add_values);
1223
974
    const uint1024_t modulus(target_basis.modulus);
1224
1225
974
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
974
    const uint512_t quotient_value = quotient_1024.lo;
1228
974
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
974
    bigfield remainder;
1231
974
    bigfield quotient;
1232
974
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
974
    } else {
1236
1237
974
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
974
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
974
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
974
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
974
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
974
    };
1250
974
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
974
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
1.55k
    for (auto& element : to_add) {
1253
1.55k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
1.55k
    }
1255
974
    return remainder;
1256
974
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1205
12
{
1206
12
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
12
    Builder* ctx = context ? context : to_mul.context;
1208
12
    reduction_check();
1209
12
    to_mul.reduction_check();
1210
1211
12
    uint512_t add_values(0);
1212
12
    bool add_constant = true;
1213
1214
12
    for (const auto& add_element : to_add) {
1215
12
        add_element.reduction_check();
1216
12
        add_values += add_element.get_value();
1217
12
        add_constant = add_constant && (add_element.is_constant());
1218
12
    }
1219
1220
12
    const uint1024_t left(get_value());
1221
12
    const uint1024_t mul_right(to_mul.get_value());
1222
12
    const uint1024_t add_right(add_values);
1223
12
    const uint1024_t modulus(target_basis.modulus);
1224
1225
12
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
12
    const uint512_t quotient_value = quotient_1024.lo;
1228
12
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
12
    bigfield remainder;
1231
12
    bigfield quotient;
1232
12
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
12
    } else {
1236
1237
12
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
12
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
12
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
12
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
12
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
12
    };
1250
12
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
12
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
12
    for (auto& element : to_add) {
1253
12
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
12
    }
1255
12
    return remainder;
1256
12
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1205
16.0k
{
1206
16.0k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
16.0k
    Builder* ctx = context ? context : to_mul.context;
1208
16.0k
    reduction_check();
1209
16.0k
    to_mul.reduction_check();
1210
1211
16.0k
    uint512_t add_values(0);
1212
16.0k
    bool add_constant = true;
1213
1214
27.0k
    for (const auto& add_element : to_add) {
1215
27.0k
        add_element.reduction_check();
1216
27.0k
        add_values += add_element.get_value();
1217
27.0k
        add_constant = add_constant && (add_element.is_constant());
1218
27.0k
    }
1219
1220
16.0k
    const uint1024_t left(get_value());
1221
16.0k
    const uint1024_t mul_right(to_mul.get_value());
1222
16.0k
    const uint1024_t add_right(add_values);
1223
16.0k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
16.0k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
16.0k
    const uint512_t quotient_value = quotient_1024.lo;
1228
16.0k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
16.0k
    bigfield remainder;
1231
16.0k
    bigfield quotient;
1232
16.0k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
16.0k
    } else {
1236
1237
16.0k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
16.0k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
16.0k
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
16.0k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
16.0k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
16.0k
    };
1250
16.0k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
16.0k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
27.0k
    for (auto& element : to_add) {
1253
27.0k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
27.0k
    }
1255
16.0k
    return remainder;
1256
16.0k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1205
228
{
1206
228
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
228
    Builder* ctx = context ? context : to_mul.context;
1208
228
    reduction_check();
1209
228
    to_mul.reduction_check();
1210
1211
228
    uint512_t add_values(0);
1212
228
    bool add_constant = true;
1213
1214
228
    for (const auto& add_element : to_add) {
1215
228
        add_element.reduction_check();
1216
228
        add_values += add_element.get_value();
1217
228
        add_constant = add_constant && (add_element.is_constant());
1218
228
    }
1219
1220
228
    const uint1024_t left(get_value());
1221
228
    const uint1024_t mul_right(to_mul.get_value());
1222
228
    const uint1024_t add_right(add_values);
1223
228
    const uint1024_t modulus(target_basis.modulus);
1224
1225
228
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
228
    const uint512_t quotient_value = quotient_1024.lo;
1228
228
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
228
    bigfield remainder;
1231
228
    bigfield quotient;
1232
228
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
228
    } else {
1236
1237
228
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
228
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
228
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
228
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
228
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
228
    };
1250
228
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
228
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
228
    for (auto& element : to_add) {
1253
228
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
228
    }
1255
228
    return remainder;
1256
228
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1205
1.30k
{
1206
1.30k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
1.30k
    Builder* ctx = context ? context : to_mul.context;
1208
1.30k
    reduction_check();
1209
1.30k
    to_mul.reduction_check();
1210
1211
1.30k
    uint512_t add_values(0);
1212
1.30k
    bool add_constant = true;
1213
1214
2.58k
    for (const auto& add_element : to_add) {
1215
2.58k
        add_element.reduction_check();
1216
2.58k
        add_values += add_element.get_value();
1217
2.58k
        add_constant = add_constant && (add_element.is_constant());
1218
2.58k
    }
1219
1220
1.30k
    const uint1024_t left(get_value());
1221
1.30k
    const uint1024_t mul_right(to_mul.get_value());
1222
1.30k
    const uint1024_t add_right(add_values);
1223
1.30k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
1.30k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
1.30k
    const uint512_t quotient_value = quotient_1024.lo;
1228
1.30k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
1.30k
    bigfield remainder;
1231
1.30k
    bigfield quotient;
1232
1.30k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
1.30k
    } else {
1236
1237
1.30k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
1.30k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
1.30k
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
1.30k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
1.30k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
1.30k
    };
1250
1.30k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
1.30k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
2.58k
    for (auto& element : to_add) {
1253
2.58k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
2.58k
    }
1255
1.30k
    return remainder;
1256
1.30k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1205
1.04k
{
1206
1.04k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
1.04k
    Builder* ctx = context ? context : to_mul.context;
1208
1.04k
    reduction_check();
1209
1.04k
    to_mul.reduction_check();
1210
1211
1.04k
    uint512_t add_values(0);
1212
1.04k
    bool add_constant = true;
1213
1214
2.06k
    for (const auto& add_element : to_add) {
1215
2.06k
        add_element.reduction_check();
1216
2.06k
        add_values += add_element.get_value();
1217
2.06k
        add_constant = add_constant && (add_element.is_constant());
1218
2.06k
    }
1219
1220
1.04k
    const uint1024_t left(get_value());
1221
1.04k
    const uint1024_t mul_right(to_mul.get_value());
1222
1.04k
    const uint1024_t add_right(add_values);
1223
1.04k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
1.04k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
1.04k
    const uint512_t quotient_value = quotient_1024.lo;
1228
1.04k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
1.04k
    bigfield remainder;
1231
1.04k
    bigfield quotient;
1232
1.04k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
1.04k
    } else {
1236
1237
1.04k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
1.04k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
1.04k
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
1.04k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
1.04k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
1.04k
    };
1250
1.04k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
1.04k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
2.06k
    for (auto& element : to_add) {
1253
2.06k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
2.06k
    }
1255
1.04k
    return remainder;
1256
1.04k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE4maddERKS8_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E4maddERKS7_RKSt6vectorIS7_SaIS7_EE
1257
1258
// MERGENOTE: Implementing dual_madd in terms of mult_madd following #729
1259
1260
/**
1261
 * @brief Performs individual reductions on the supplied elements as well as more complex reductions to prevent CRT
1262
 * modulus overflow and to fit the quotient inside the range proof
1263
 *
1264
 *
1265
 * @tparam Builder builder
1266
 * @tparam T basefield
1267
 * @param mul_left
1268
 * @param mul_right
1269
 * @param to_add
1270
 */
1271
template <typename Builder, typename T>
1272
void bigfield<Builder, T>::perform_reductions_for_mult_madd(std::vector<bigfield>& mul_left,
1273
                                                            std::vector<bigfield>& mul_right,
1274
                                                            const std::vector<bigfield>& to_add)
1275
323k
{
1276
323k
    ASSERT(mul_left.size() == mul_right.size());
1277
323k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
323k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
0
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
0
    std::vector<uint512_t> max_values_left;
1283
0
    std::vector<uint512_t> max_values_right;
1284
1285
0
    max_values_left.reserve(number_of_products);
1286
0
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
721k
    for (auto& left_element : mul_left) {
1289
721k
        left_element.reduction_check();
1290
721k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
721k
    }
1292
1293
721k
    for (auto& right_element : mul_right) {
1294
721k
        right_element.reduction_check();
1295
721k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
721k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
0
    bool reduction_required;
1305
0
    reduction_required = std::get<0>(
1306
0
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
323k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
1
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
1
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
1
                                  std::vector<bigfield>& m_left,
1320
1
                                  std::vector<bigfield>& m_right,
1321
1
                                  size_t number_of_products) {
1322
1
            maxval_updates.resize(0);
1323
1
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
2
            for (size_t i = 0; i < number_of_products; i++) {
1326
1
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
1
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
1
                uint1024_t original_product = original_left * original_right;
1329
1
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
1
                } else {
1333
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
1
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
1
                    maxval_updates.emplace_back(
1338
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
1
                }
1340
1
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
1
                } else {
1344
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
1
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
1
                    maxval_updates.emplace_back(
1349
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
1
                }
1351
1
            }
1352
1
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRS7_ISt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESaISJ_EESA_SA_mE_clESM_SA_SA_m
Line
Count
Source
1321
1
                                  size_t number_of_products) {
1322
1
            maxval_updates.resize(0);
1323
1
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
2
            for (size_t i = 0; i < number_of_products; i++) {
1326
1
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
1
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
1
                uint1024_t original_product = original_left * original_right;
1329
1
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
1
                } else {
1333
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
1
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
1
                    maxval_updates.emplace_back(
1338
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
1
                }
1340
1
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
1
                } else {
1344
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
1
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
1
                    maxval_updates.emplace_back(
1349
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
1
                }
1351
1
            }
1352
1
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRS7_ISt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESaISJ_EESA_SA_mE_clESM_SA_SA_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ENKUlRS9_ISt5tupleIJNS_7numeric5uintxINSH_INSG_9uint256_tEEEEEmmEESaISL_EESC_SC_mE_clESO_SC_SC_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
1353
1354
1
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
2
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
2
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
2
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRSt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESK_E_clESK_SK_
Line
Count
Source
1355
2
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
2
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
2
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRSt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESK_E_clESK_SK_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ENKUlRSt5tupleIJNS_7numeric5uintxINSH_INSG_9uint256_tEEEEEmmEESM_E_clESM_SM_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
2
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
1
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
1
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
1
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
1
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
1
            if (multiplicand_index == 0) {
1376
1
                mul_left[largest_update_product_index].self_reduce();
1377
1
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
2
            for (size_t i = 0; i < number_of_products; i++) {
1382
1
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
1
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
1
            }
1385
1
            reduction_required = std::get<0>(
1386
1
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
1
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
1
    }
1392
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Line
Count
Source
1275
295k
{
1276
295k
    ASSERT(mul_left.size() == mul_right.size());
1277
295k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
295k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
295k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
295k
    std::vector<uint512_t> max_values_left;
1283
295k
    std::vector<uint512_t> max_values_right;
1284
1285
295k
    max_values_left.reserve(number_of_products);
1286
295k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
649k
    for (auto& left_element : mul_left) {
1289
649k
        left_element.reduction_check();
1290
649k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
649k
    }
1292
1293
649k
    for (auto& right_element : mul_right) {
1294
649k
        right_element.reduction_check();
1295
649k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
649k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
295k
    bool reduction_required;
1305
295k
    reduction_required = std::get<0>(
1306
295k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
295k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
1
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
1
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
1
                                  std::vector<bigfield>& m_left,
1320
1
                                  std::vector<bigfield>& m_right,
1321
1
                                  size_t number_of_products) {
1322
1
            maxval_updates.resize(0);
1323
1
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
1
            for (size_t i = 0; i < number_of_products; i++) {
1326
1
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
1
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
1
                uint1024_t original_product = original_left * original_right;
1329
1
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
1
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
1
                } else {
1333
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
1
                    if (new_product > original_product) {
1335
1
                        throw_or_abort("bigfield: This should never happen");
1336
1
                    }
1337
1
                    maxval_updates.emplace_back(
1338
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
1
                }
1340
1
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
1
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
1
                } else {
1344
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
1
                    if (new_product > original_product) {
1346
1
                        throw_or_abort("bigfield: This should never happen");
1347
1
                    }
1348
1
                    maxval_updates.emplace_back(
1349
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
1
                }
1351
1
            }
1352
1
        };
1353
1354
1
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
1
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
1
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
1
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
2
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
1
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
1
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
1
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
1
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
1
            if (multiplicand_index == 0) {
1376
1
                mul_left[largest_update_product_index].self_reduce();
1377
1
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
2
            for (size_t i = 0; i < number_of_products; i++) {
1382
1
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
1
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
1
            }
1385
1
            reduction_required = std::get<0>(
1386
1
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
1
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
1
    }
1392
295k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
Line
Count
Source
1275
1.29k
{
1276
1.29k
    ASSERT(mul_left.size() == mul_right.size());
1277
1.29k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
1.29k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
1.29k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
1.29k
    std::vector<uint512_t> max_values_left;
1283
1.29k
    std::vector<uint512_t> max_values_right;
1284
1285
1.29k
    max_values_left.reserve(number_of_products);
1286
1.29k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
3.15k
    for (auto& left_element : mul_left) {
1289
3.15k
        left_element.reduction_check();
1290
3.15k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
3.15k
    }
1292
1293
3.15k
    for (auto& right_element : mul_right) {
1294
3.15k
        right_element.reduction_check();
1295
3.15k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
3.15k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
1.29k
    bool reduction_required;
1305
1.29k
    reduction_required = std::get<0>(
1306
1.29k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
1.29k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
1.29k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
Line
Count
Source
1275
22.4k
{
1276
22.4k
    ASSERT(mul_left.size() == mul_right.size());
1277
22.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
22.4k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
22.4k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
22.4k
    std::vector<uint512_t> max_values_left;
1283
22.4k
    std::vector<uint512_t> max_values_right;
1284
1285
22.4k
    max_values_left.reserve(number_of_products);
1286
22.4k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
55.8k
    for (auto& left_element : mul_left) {
1289
55.8k
        left_element.reduction_check();
1290
55.8k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
55.8k
    }
1292
1293
55.8k
    for (auto& right_element : mul_right) {
1294
55.8k
        right_element.reduction_check();
1295
55.8k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
55.8k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
22.4k
    bool reduction_required;
1305
22.4k
    reduction_required = std::get<0>(
1306
22.4k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
22.4k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
22.4k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
Line
Count
Source
1275
2.23k
{
1276
2.23k
    ASSERT(mul_left.size() == mul_right.size());
1277
2.23k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
2.23k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
2.23k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
2.23k
    std::vector<uint512_t> max_values_left;
1283
2.23k
    std::vector<uint512_t> max_values_right;
1284
1285
2.23k
    max_values_left.reserve(number_of_products);
1286
2.23k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
7.01k
    for (auto& left_element : mul_left) {
1289
7.01k
        left_element.reduction_check();
1290
7.01k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
7.01k
    }
1292
1293
7.01k
    for (auto& right_element : mul_right) {
1294
7.01k
        right_element.reduction_check();
1295
7.01k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
7.01k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
2.23k
    bool reduction_required;
1305
2.23k
    reduction_required = std::get<0>(
1306
2.23k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
2.23k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
2.23k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
Line
Count
Source
1275
1.78k
{
1276
1.78k
    ASSERT(mul_left.size() == mul_right.size());
1277
1.78k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
1.78k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
1.78k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
1.78k
    std::vector<uint512_t> max_values_left;
1283
1.78k
    std::vector<uint512_t> max_values_right;
1284
1285
1.78k
    max_values_left.reserve(number_of_products);
1286
1.78k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
5.60k
    for (auto& left_element : mul_left) {
1289
5.60k
        left_element.reduction_check();
1290
5.60k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
5.60k
    }
1292
1293
5.60k
    for (auto& right_element : mul_right) {
1294
5.60k
        right_element.reduction_check();
1295
5.60k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
5.60k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
1.78k
    bool reduction_required;
1305
1.78k
    reduction_required = std::get<0>(
1306
1.78k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
1.78k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
1.78k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
1393
1394
/**
1395
 * Evaluate the sum of products and additional values safely.
1396
 *
1397
 * @param mul_left Vector of bigfield multiplicands
1398
 * @param mul_right Vector of bigfield multipliers
1399
 * @param to_add Vector of bigfield elements to add to the sum of products
1400
 *
1401
 * @return A reduced value that is the sum of all products and to_add values
1402
 * */
1403
template <typename Builder, typename T>
1404
bigfield<Builder, T> bigfield<Builder, T>::mult_madd(const std::vector<bigfield>& mul_left,
1405
                                                     const std::vector<bigfield>& mul_right,
1406
                                                     const std::vector<bigfield>& to_add,
1407
                                                     bool fix_remainder_to_zero)
1408
323k
{
1409
323k
    ASSERT(mul_left.size() == mul_right.size());
1410
323k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
323k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
0
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
0
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
0
    const size_t number_of_products = mul_left.size();
1417
1418
0
    const uint1024_t modulus(target_basis.modulus);
1419
0
    uint1024_t worst_case_product_sum(0);
1420
0
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
0
    bool add_constant = true;
1424
0
    std::vector<bigfield> new_to_add;
1425
1426
0
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
721k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
721k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
721k
    }
1431
569k
    for (auto& element : to_add) {
1432
569k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
569k
    }
1434
1435
569k
    for (const auto& add_element : to_add) {
1436
569k
        add_element.reduction_check();
1437
569k
        if (add_element.is_constant()) {
1438
80
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
569k
        } else {
1440
569k
            add_constant = false;
1441
569k
            new_to_add.push_back(add_element);
1442
569k
        }
1443
569k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
0
    uint1024_t sum_of_constant_products(0);
1448
0
    std::vector<bigfield> new_input_left;
1449
0
    std::vector<bigfield> new_input_right;
1450
0
    bool product_sum_constant = true;
1451
1.04M
    for (size_t i = 0; i < number_of_products; i++) {
1452
721k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
721k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
721k
            new_input_left.push_back(mutable_mul_left[i]);
1459
721k
            new_input_right.push_back(mutable_mul_right[i]);
1460
721k
            product_sum_constant = false;
1461
721k
        }
1462
721k
    }
1463
1464
0
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
323k
    for (auto& el : mutable_mul_left) {
1467
323k
        if (el.context) {
1468
323k
            ctx = el.context;
1469
323k
            break;
1470
323k
        }
1471
323k
    }
1472
    // And on the right
1473
323k
    if (!ctx) {
1474
1
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
1
    }
1481
323k
    if (product_sum_constant) {
1482
1
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
1
            const auto [quotient_1024, remainder_1024] =
1485
1
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
1
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
1
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
1
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
323k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
323k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
323k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
80
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
80
    }
1522
    // Compute added sum
1523
323k
    uint1024_t add_right_final_sum(0);
1524
323k
    uint1024_t add_right_maximum(0);
1525
569k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
569k
        add_element.reduction_check();
1528
569k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
569k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
569k
    }
1532
323k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
323k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
323k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
323k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
0
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
0
    uint1024_t sum_of_products_final(0);
1545
1.04M
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
721k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
721k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
0
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
0
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
323k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
297k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
297k
    }
1561
0
    const uint512_t quotient_value = quotient_1024.lo;
1562
0
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
0
    bigfield remainder;
1565
0
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
0
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
323k
    if (fix_remainder_to_zero) {
1570
297k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
297k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
297k
    } else {
1575
25.8k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
25.8k
    }
1577
1578
0
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
0
    remainder.set_origin_tag(new_tag);
1581
0
    return remainder;
1582
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Line
Count
Source
1408
295k
{
1409
295k
    ASSERT(mul_left.size() == mul_right.size());
1410
295k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
295k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
295k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
295k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
295k
    const size_t number_of_products = mul_left.size();
1417
1418
295k
    const uint1024_t modulus(target_basis.modulus);
1419
295k
    uint1024_t worst_case_product_sum(0);
1420
295k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
295k
    bool add_constant = true;
1424
295k
    std::vector<bigfield> new_to_add;
1425
1426
295k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
649k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
649k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
649k
    }
1431
536k
    for (auto& element : to_add) {
1432
536k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
536k
    }
1434
1435
536k
    for (const auto& add_element : to_add) {
1436
536k
        add_element.reduction_check();
1437
536k
        if (add_element.is_constant()) {
1438
69
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
536k
        } else {
1440
536k
            add_constant = false;
1441
536k
            new_to_add.push_back(add_element);
1442
536k
        }
1443
536k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
295k
    uint1024_t sum_of_constant_products(0);
1448
295k
    std::vector<bigfield> new_input_left;
1449
295k
    std::vector<bigfield> new_input_right;
1450
295k
    bool product_sum_constant = true;
1451
945k
    for (size_t i = 0; i < number_of_products; i++) {
1452
649k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
649k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
649k
            new_input_left.push_back(mutable_mul_left[i]);
1459
649k
            new_input_right.push_back(mutable_mul_right[i]);
1460
649k
            product_sum_constant = false;
1461
649k
        }
1462
649k
    }
1463
1464
295k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
295k
    for (auto& el : mutable_mul_left) {
1467
295k
        if (el.context) {
1468
295k
            ctx = el.context;
1469
295k
            break;
1470
295k
        }
1471
295k
    }
1472
    // And on the right
1473
295k
    if (!ctx) {
1474
1
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
1
    }
1481
295k
    if (product_sum_constant) {
1482
1
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
1
            const auto [quotient_1024, remainder_1024] =
1485
1
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
1
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
1
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
1
            result.set_origin_tag(new_tag);
1489
1
            return result;
1490
1
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
1
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
295k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
295k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
295k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
69
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
69
    }
1522
    // Compute added sum
1523
295k
    uint1024_t add_right_final_sum(0);
1524
295k
    uint1024_t add_right_maximum(0);
1525
536k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
536k
        add_element.reduction_check();
1528
536k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
536k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
536k
    }
1532
295k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
295k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
295k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
295k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
295k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
295k
    uint1024_t sum_of_products_final(0);
1545
945k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
649k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
649k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
295k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
295k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
295k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
274k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
274k
    }
1561
295k
    const uint512_t quotient_value = quotient_1024.lo;
1562
295k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
295k
    bigfield remainder;
1565
295k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
295k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
295k
    if (fix_remainder_to_zero) {
1570
274k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
274k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
274k
    } else {
1575
21.4k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
21.4k
    }
1577
1578
295k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
295k
    remainder.set_origin_tag(new_tag);
1581
295k
    return remainder;
1582
295k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS8_SaIS8_EESD_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
Line
Count
Source
1408
1.29k
{
1409
1.29k
    ASSERT(mul_left.size() == mul_right.size());
1410
1.29k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
1.29k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
1.29k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
1.29k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
1.29k
    const size_t number_of_products = mul_left.size();
1417
1418
1.29k
    const uint1024_t modulus(target_basis.modulus);
1419
1.29k
    uint1024_t worst_case_product_sum(0);
1420
1.29k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
1.29k
    bool add_constant = true;
1424
1.29k
    std::vector<bigfield> new_to_add;
1425
1426
1.29k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
3.15k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
3.15k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
3.15k
    }
1431
1.37k
    for (auto& element : to_add) {
1432
1.37k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
1.37k
    }
1434
1435
1.37k
    for (const auto& add_element : to_add) {
1436
1.37k
        add_element.reduction_check();
1437
1.37k
        if (add_element.is_constant()) {
1438
3
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
1.37k
        } else {
1440
1.37k
            add_constant = false;
1441
1.37k
            new_to_add.push_back(add_element);
1442
1.37k
        }
1443
1.37k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
1.29k
    uint1024_t sum_of_constant_products(0);
1448
1.29k
    std::vector<bigfield> new_input_left;
1449
1.29k
    std::vector<bigfield> new_input_right;
1450
1.29k
    bool product_sum_constant = true;
1451
4.44k
    for (size_t i = 0; i < number_of_products; i++) {
1452
3.15k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
3.15k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
3.15k
            new_input_left.push_back(mutable_mul_left[i]);
1459
3.15k
            new_input_right.push_back(mutable_mul_right[i]);
1460
3.15k
            product_sum_constant = false;
1461
3.15k
        }
1462
3.15k
    }
1463
1464
1.29k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
1.29k
    for (auto& el : mutable_mul_left) {
1467
1.29k
        if (el.context) {
1468
1.29k
            ctx = el.context;
1469
1.29k
            break;
1470
1.29k
        }
1471
1.29k
    }
1472
    // And on the right
1473
1.29k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
1.29k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
1.29k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
1.29k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
1.29k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
3
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
3
    }
1522
    // Compute added sum
1523
1.29k
    uint1024_t add_right_final_sum(0);
1524
1.29k
    uint1024_t add_right_maximum(0);
1525
1.37k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
1.37k
        add_element.reduction_check();
1528
1.37k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
1.37k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
1.37k
    }
1532
1.29k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
1.29k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
1.29k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
1.29k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
1.29k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
1.29k
    uint1024_t sum_of_products_final(0);
1545
4.44k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
3.15k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
3.15k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
1.29k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
1.29k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
1.29k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
1.09k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
1.09k
    }
1561
1.29k
    const uint512_t quotient_value = quotient_1024.lo;
1562
1.29k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
1.29k
    bigfield remainder;
1565
1.29k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
1.29k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
1.29k
    if (fix_remainder_to_zero) {
1570
1.09k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
1.09k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
1.09k
    } else {
1575
192
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
192
    }
1577
1578
1.29k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
1.29k
    remainder.set_origin_tag(new_tag);
1581
1.29k
    return remainder;
1582
1.29k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
Line
Count
Source
1408
22.4k
{
1409
22.4k
    ASSERT(mul_left.size() == mul_right.size());
1410
22.4k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
22.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
22.4k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
22.4k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
22.4k
    const size_t number_of_products = mul_left.size();
1417
1418
22.4k
    const uint1024_t modulus(target_basis.modulus);
1419
22.4k
    uint1024_t worst_case_product_sum(0);
1420
22.4k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
22.4k
    bool add_constant = true;
1424
22.4k
    std::vector<bigfield> new_to_add;
1425
1426
22.4k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
55.8k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
55.8k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
55.8k
    }
1431
26.2k
    for (auto& element : to_add) {
1432
26.2k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
26.2k
    }
1434
1435
26.2k
    for (const auto& add_element : to_add) {
1436
26.2k
        add_element.reduction_check();
1437
26.2k
        if (add_element.is_constant()) {
1438
0
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
26.2k
        } else {
1440
26.2k
            add_constant = false;
1441
26.2k
            new_to_add.push_back(add_element);
1442
26.2k
        }
1443
26.2k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
22.4k
    uint1024_t sum_of_constant_products(0);
1448
22.4k
    std::vector<bigfield> new_input_left;
1449
22.4k
    std::vector<bigfield> new_input_right;
1450
22.4k
    bool product_sum_constant = true;
1451
78.3k
    for (size_t i = 0; i < number_of_products; i++) {
1452
55.8k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
55.8k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
55.8k
            new_input_left.push_back(mutable_mul_left[i]);
1459
55.8k
            new_input_right.push_back(mutable_mul_right[i]);
1460
55.8k
            product_sum_constant = false;
1461
55.8k
        }
1462
55.8k
    }
1463
1464
22.4k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
22.4k
    for (auto& el : mutable_mul_left) {
1467
22.4k
        if (el.context) {
1468
22.4k
            ctx = el.context;
1469
22.4k
            break;
1470
22.4k
        }
1471
22.4k
    }
1472
    // And on the right
1473
22.4k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
22.4k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
22.4k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
22.4k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
22.4k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
0
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
0
    }
1522
    // Compute added sum
1523
22.4k
    uint1024_t add_right_final_sum(0);
1524
22.4k
    uint1024_t add_right_maximum(0);
1525
26.2k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
26.2k
        add_element.reduction_check();
1528
26.2k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
26.2k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
26.2k
    }
1532
22.4k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
22.4k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
22.4k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
22.4k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
22.4k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
22.4k
    uint1024_t sum_of_products_final(0);
1545
78.3k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
55.8k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
55.8k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
22.4k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
22.4k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
22.4k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
18.8k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
18.8k
    }
1561
22.4k
    const uint512_t quotient_value = quotient_1024.lo;
1562
22.4k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
22.4k
    bigfield remainder;
1565
22.4k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
22.4k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
22.4k
    if (fix_remainder_to_zero) {
1570
18.8k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
18.8k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
18.8k
    } else {
1575
3.64k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
3.64k
    }
1577
1578
22.4k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
22.4k
    remainder.set_origin_tag(new_tag);
1581
22.4k
    return remainder;
1582
22.4k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
Line
Count
Source
1408
2.23k
{
1409
2.23k
    ASSERT(mul_left.size() == mul_right.size());
1410
2.23k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
2.23k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
2.23k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
2.23k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
2.23k
    const size_t number_of_products = mul_left.size();
1417
1418
2.23k
    const uint1024_t modulus(target_basis.modulus);
1419
2.23k
    uint1024_t worst_case_product_sum(0);
1420
2.23k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
2.23k
    bool add_constant = true;
1424
2.23k
    std::vector<bigfield> new_to_add;
1425
1426
2.23k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
7.01k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
7.01k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
7.01k
    }
1431
3.19k
    for (auto& element : to_add) {
1432
3.19k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
3.19k
    }
1434
1435
3.19k
    for (const auto& add_element : to_add) {
1436
3.19k
        add_element.reduction_check();
1437
3.19k
        if (add_element.is_constant()) {
1438
4
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
3.18k
        } else {
1440
3.18k
            add_constant = false;
1441
3.18k
            new_to_add.push_back(add_element);
1442
3.18k
        }
1443
3.19k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
2.23k
    uint1024_t sum_of_constant_products(0);
1448
2.23k
    std::vector<bigfield> new_input_left;
1449
2.23k
    std::vector<bigfield> new_input_right;
1450
2.23k
    bool product_sum_constant = true;
1451
9.24k
    for (size_t i = 0; i < number_of_products; i++) {
1452
7.01k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
7.01k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
7.01k
            new_input_left.push_back(mutable_mul_left[i]);
1459
7.01k
            new_input_right.push_back(mutable_mul_right[i]);
1460
7.01k
            product_sum_constant = false;
1461
7.01k
        }
1462
7.01k
    }
1463
1464
2.23k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
2.23k
    for (auto& el : mutable_mul_left) {
1467
2.23k
        if (el.context) {
1468
2.23k
            ctx = el.context;
1469
2.23k
            break;
1470
2.23k
        }
1471
2.23k
    }
1472
    // And on the right
1473
2.23k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
2.23k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
2.23k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
2.23k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
2.23k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
4
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
4
    }
1522
    // Compute added sum
1523
2.23k
    uint1024_t add_right_final_sum(0);
1524
2.23k
    uint1024_t add_right_maximum(0);
1525
3.19k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
3.19k
        add_element.reduction_check();
1528
3.19k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
3.19k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
3.19k
    }
1532
2.23k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
2.23k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
2.23k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
2.23k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
2.23k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
2.23k
    uint1024_t sum_of_products_final(0);
1545
9.24k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
7.01k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
7.01k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
2.23k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
2.23k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
2.23k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
1.91k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
1.91k
    }
1561
2.23k
    const uint512_t quotient_value = quotient_1024.lo;
1562
2.23k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
2.23k
    bigfield remainder;
1565
2.23k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
2.23k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
2.23k
    if (fix_remainder_to_zero) {
1570
1.91k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
1.91k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
1.91k
    } else {
1575
320
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
320
    }
1577
1578
2.23k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
2.23k
    remainder.set_origin_tag(new_tag);
1581
2.23k
    return remainder;
1582
2.23k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
Line
Count
Source
1408
1.78k
{
1409
1.78k
    ASSERT(mul_left.size() == mul_right.size());
1410
1.78k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
1.78k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
1.78k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
1.78k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
1.78k
    const size_t number_of_products = mul_left.size();
1417
1418
1.78k
    const uint1024_t modulus(target_basis.modulus);
1419
1.78k
    uint1024_t worst_case_product_sum(0);
1420
1.78k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
1.78k
    bool add_constant = true;
1424
1.78k
    std::vector<bigfield> new_to_add;
1425
1426
1.78k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
5.60k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
5.60k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
5.60k
    }
1431
2.55k
    for (auto& element : to_add) {
1432
2.55k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
2.55k
    }
1434
1435
2.55k
    for (const auto& add_element : to_add) {
1436
2.55k
        add_element.reduction_check();
1437
2.55k
        if (add_element.is_constant()) {
1438
4
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
2.54k
        } else {
1440
2.54k
            add_constant = false;
1441
2.54k
            new_to_add.push_back(add_element);
1442
2.54k
        }
1443
2.55k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
1.78k
    uint1024_t sum_of_constant_products(0);
1448
1.78k
    std::vector<bigfield> new_input_left;
1449
1.78k
    std::vector<bigfield> new_input_right;
1450
1.78k
    bool product_sum_constant = true;
1451
7.39k
    for (size_t i = 0; i < number_of_products; i++) {
1452
5.60k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
5.60k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
5.60k
            new_input_left.push_back(mutable_mul_left[i]);
1459
5.60k
            new_input_right.push_back(mutable_mul_right[i]);
1460
5.60k
            product_sum_constant = false;
1461
5.60k
        }
1462
5.60k
    }
1463
1464
1.78k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
1.78k
    for (auto& el : mutable_mul_left) {
1467
1.78k
        if (el.context) {
1468
1.78k
            ctx = el.context;
1469
1.78k
            break;
1470
1.78k
        }
1471
1.78k
    }
1472
    // And on the right
1473
1.78k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
1.78k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
1.78k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
1.78k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
1.78k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
4
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
4
    }
1522
    // Compute added sum
1523
1.78k
    uint1024_t add_right_final_sum(0);
1524
1.78k
    uint1024_t add_right_maximum(0);
1525
2.55k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
2.55k
        add_element.reduction_check();
1528
2.55k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
2.55k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
2.55k
    }
1532
1.78k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
1.78k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
1.78k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
1.78k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
1.78k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
1.78k
    uint1024_t sum_of_products_final(0);
1545
7.39k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
5.60k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
5.60k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
1.78k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
1.78k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
1.78k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
1.53k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
1.53k
    }
1561
1.78k
    const uint512_t quotient_value = quotient_1024.lo;
1562
1.78k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
1.78k
    bigfield remainder;
1565
1.78k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
1.78k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
1.78k
    if (fix_remainder_to_zero) {
1570
1.53k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
1.53k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
1.53k
    } else {
1575
256
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
256
    }
1577
1578
1.78k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
1.78k
    remainder.set_origin_tag(new_tag);
1581
1.78k
    return remainder;
1582
1.78k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS8_SaIS8_EESD_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
1583
1584
/**
1585
 * Compute (left_a * right_a) + (left_b * right_b) + ...to_add = c mod p
1586
 *
1587
 * This is cheaper than two multiplication operations, as the above only requires one quotient/remainder
1588
 **/
1589
template <typename Builder, typename T>
1590
bigfield<Builder, T> bigfield<Builder, T>::dual_madd(const bigfield& left_a,
1591
                                                     const bigfield& right_a,
1592
                                                     const bigfield& left_b,
1593
                                                     const bigfield& right_b,
1594
                                                     const std::vector<bigfield>& to_add)
1595
1
{
1596
1
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1597
0
    left_a.reduction_check();
1598
0
    right_a.reduction_check();
1599
0
    left_b.reduction_check();
1600
0
    right_b.reduction_check();
1601
1602
0
    std::vector<bigfield> mul_left = { left_a, left_b };
1603
0
    std::vector<bigfield> mul_right = { right_a, right_b };
1604
1605
0
    return mult_madd(mul_left, mul_right, to_add);
1606
1
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
1595
1
{
1596
1
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1597
1
    left_a.reduction_check();
1598
1
    right_a.reduction_check();
1599
1
    left_b.reduction_check();
1600
1
    right_b.reduction_check();
1601
1602
1
    std::vector<bigfield> mul_left = { left_a, left_b };
1603
1
    std::vector<bigfield> mul_right = { right_a, right_b };
1604
1605
1
    return mult_madd(mul_left, mul_right, to_add);
1606
1
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9dual_maddERKS8_SA_SA_SA_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9dual_maddERKS8_SA_SA_SA_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
1607
1608
/**
1609
 * multiply, subtract, divide.
1610
 * This method computes:
1611
 *
1612
 * result = -(\sum{mul_left[i] * mul_right[i]} + ...to_add) / divisor
1613
 *
1614
 * Algorithm is constructed in this way to ensure that all computed terms are positive
1615
 *
1616
 * i.e. we evaluate:
1617
 * result * divisor + (\sum{mul_left[i] * mul_right[i]) + ...to_add) = 0
1618
 *
1619
 * It is critical that ALL the terms on the LHS are positive to eliminate the possiblity of underflows
1620
 * when calling `evaluate_multiple_multiply_add`
1621
 *
1622
 * only requires one quotient and remainder + overflow limbs
1623
 *
1624
 * We proxy this to mult_madd, so it only requires one quotient and remainder + overflow limbs
1625
 **/
1626
template <typename Builder, typename T>
1627
bigfield<Builder, T> bigfield<Builder, T>::msub_div(const std::vector<bigfield>& mul_left,
1628
                                                    const std::vector<bigfield>& mul_right,
1629
                                                    const bigfield& divisor,
1630
                                                    const std::vector<bigfield>& to_sub,
1631
                                                    bool enable_divisor_nz_check)
1632
296k
{
1633
    // Check the basics
1634
296k
    ASSERT(mul_left.size() == mul_right.size());
1635
296k
    ASSERT(divisor.get_value() != 0);
1636
1637
0
    OriginTag new_tag = divisor.get_origin_tag();
1638
354k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
354k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
354k
    }
1641
542k
    for (auto& element : to_sub) {
1642
542k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
542k
    }
1644
    // Gett he context
1645
0
    Builder* ctx = divisor.context;
1646
296k
    if (ctx == NULL) {
1647
1
        for (auto& el : mul_left) {
1648
1
            if (el.context != NULL) {
1649
1
                ctx = el.context;
1650
1
                break;
1651
1
            }
1652
1
        }
1653
1
    }
1654
296k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
296k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
0
    const size_t num_multiplications = mul_left.size();
1671
0
    native product_native = 0;
1672
0
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
296k
    if (enable_divisor_nz_check) {
1676
1
        divisor.assert_is_not_equal(zero());
1677
1
    }
1678
1679
    // Compute the sum of products
1680
650k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
354k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
354k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
354k
        product_native += (mul_left_native * -mul_right_native);
1684
354k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
354k
    }
1686
1687
    // Compute the sum of to_sub
1688
0
    native sub_native(0);
1689
0
    bool sub_constant = true;
1690
542k
    for (const auto& sub : to_sub) {
1691
542k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
542k
        sub_constant = sub_constant && sub.is_constant();
1693
542k
    }
1694
1695
0
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
0
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
0
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
296k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
296k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
0
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
0
    std::vector<bigfield> eval_left{ result };
1714
0
    std::vector<bigfield> eval_right{ divisor };
1715
354k
    for (const auto& in : mul_left) {
1716
354k
        eval_left.emplace_back(in);
1717
354k
    }
1718
354k
    for (const auto& in : mul_right) {
1719
354k
        eval_right.emplace_back(in);
1720
354k
    }
1721
1722
0
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
0
    result.set_origin_tag(new_tag);
1725
0
    return result;
1726
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Line
Count
Source
1632
272k
{
1633
    // Check the basics
1634
272k
    ASSERT(mul_left.size() == mul_right.size());
1635
272k
    ASSERT(divisor.get_value() != 0);
1636
1637
272k
    OriginTag new_tag = divisor.get_origin_tag();
1638
320k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
320k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
320k
    }
1641
513k
    for (auto& element : to_sub) {
1642
513k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
513k
    }
1644
    // Gett he context
1645
272k
    Builder* ctx = divisor.context;
1646
272k
    if (ctx == NULL) {
1647
1
        for (auto& el : mul_left) {
1648
1
            if (el.context != NULL) {
1649
1
                ctx = el.context;
1650
1
                break;
1651
1
            }
1652
1
        }
1653
1
    }
1654
272k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
272k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
272k
    const size_t num_multiplications = mul_left.size();
1671
272k
    native product_native = 0;
1672
272k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
272k
    if (enable_divisor_nz_check) {
1676
1
        divisor.assert_is_not_equal(zero());
1677
1
    }
1678
1679
    // Compute the sum of products
1680
593k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
320k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
320k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
320k
        product_native += (mul_left_native * -mul_right_native);
1684
320k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
320k
    }
1686
1687
    // Compute the sum of to_sub
1688
272k
    native sub_native(0);
1689
272k
    bool sub_constant = true;
1690
513k
    for (const auto& sub : to_sub) {
1691
513k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
513k
        sub_constant = sub_constant && sub.is_constant();
1693
513k
    }
1694
1695
272k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
272k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
272k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
272k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
272k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
272k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
272k
    std::vector<bigfield> eval_left{ result };
1714
272k
    std::vector<bigfield> eval_right{ divisor };
1715
320k
    for (const auto& in : mul_left) {
1716
320k
        eval_left.emplace_back(in);
1717
320k
    }
1718
320k
    for (const auto& in : mul_right) {
1719
320k
        eval_right.emplace_back(in);
1720
320k
    }
1721
1722
272k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
272k
    result.set_origin_tag(new_tag);
1725
272k
    return result;
1726
272k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS8_SaIS8_EESD_RKS8_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
Line
Count
Source
1632
1.09k
{
1633
    // Check the basics
1634
1.09k
    ASSERT(mul_left.size() == mul_right.size());
1635
1.09k
    ASSERT(divisor.get_value() != 0);
1636
1637
1.09k
    OriginTag new_tag = divisor.get_origin_tag();
1638
1.47k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
1.47k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
1.47k
    }
1641
1.17k
    for (auto& element : to_sub) {
1642
1.17k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
1.17k
    }
1644
    // Gett he context
1645
1.09k
    Builder* ctx = divisor.context;
1646
1.09k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
1.09k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
1.09k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
1.09k
    const size_t num_multiplications = mul_left.size();
1671
1.09k
    native product_native = 0;
1672
1.09k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
1.09k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
2.56k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
1.47k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
1.47k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
1.47k
        product_native += (mul_left_native * -mul_right_native);
1684
1.47k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
1.47k
    }
1686
1687
    // Compute the sum of to_sub
1688
1.09k
    native sub_native(0);
1689
1.09k
    bool sub_constant = true;
1690
1.17k
    for (const auto& sub : to_sub) {
1691
1.17k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
1.17k
        sub_constant = sub_constant && sub.is_constant();
1693
1.17k
    }
1694
1695
1.09k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
1.09k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
1.09k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
1.09k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
1.09k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
1.09k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
1.09k
    std::vector<bigfield> eval_left{ result };
1714
1.09k
    std::vector<bigfield> eval_right{ divisor };
1715
1.47k
    for (const auto& in : mul_left) {
1716
1.47k
        eval_left.emplace_back(in);
1717
1.47k
    }
1718
1.47k
    for (const auto& in : mul_right) {
1719
1.47k
        eval_right.emplace_back(in);
1720
1.47k
    }
1721
1722
1.09k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
1.09k
    result.set_origin_tag(new_tag);
1725
1.09k
    return result;
1726
1.09k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
Line
Count
Source
1632
18.5k
{
1633
    // Check the basics
1634
18.5k
    ASSERT(mul_left.size() == mul_right.size());
1635
18.5k
    ASSERT(divisor.get_value() != 0);
1636
1637
18.5k
    OriginTag new_tag = divisor.get_origin_tag();
1638
25.8k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
25.8k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
25.8k
    }
1641
22.3k
    for (auto& element : to_sub) {
1642
22.3k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
22.3k
    }
1644
    // Gett he context
1645
18.5k
    Builder* ctx = divisor.context;
1646
18.5k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
18.5k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
18.5k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
18.5k
    const size_t num_multiplications = mul_left.size();
1671
18.5k
    native product_native = 0;
1672
18.5k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
18.5k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
44.4k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
25.8k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
25.8k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
25.8k
        product_native += (mul_left_native * -mul_right_native);
1684
25.8k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
25.8k
    }
1686
1687
    // Compute the sum of to_sub
1688
18.5k
    native sub_native(0);
1689
18.5k
    bool sub_constant = true;
1690
22.3k
    for (const auto& sub : to_sub) {
1691
22.3k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
22.3k
        sub_constant = sub_constant && sub.is_constant();
1693
22.3k
    }
1694
1695
18.5k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
18.5k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
18.5k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
18.5k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
18.5k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
18.5k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
18.5k
    std::vector<bigfield> eval_left{ result };
1714
18.5k
    std::vector<bigfield> eval_right{ divisor };
1715
25.8k
    for (const auto& in : mul_left) {
1716
25.8k
        eval_left.emplace_back(in);
1717
25.8k
    }
1718
25.8k
    for (const auto& in : mul_right) {
1719
25.8k
        eval_right.emplace_back(in);
1720
25.8k
    }
1721
1722
18.5k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
18.5k
    result.set_origin_tag(new_tag);
1725
18.5k
    return result;
1726
18.5k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
Line
Count
Source
1632
1.91k
{
1633
    // Check the basics
1634
1.91k
    ASSERT(mul_left.size() == mul_right.size());
1635
1.91k
    ASSERT(divisor.get_value() != 0);
1636
1637
1.91k
    OriginTag new_tag = divisor.get_origin_tag();
1638
3.81k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
3.81k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
3.81k
    }
1641
2.86k
    for (auto& element : to_sub) {
1642
2.86k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
2.86k
    }
1644
    // Gett he context
1645
1.91k
    Builder* ctx = divisor.context;
1646
1.91k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
1.91k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
1.91k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
1.91k
    const size_t num_multiplications = mul_left.size();
1671
1.91k
    native product_native = 0;
1672
1.91k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
1.91k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
5.72k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
3.81k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
3.81k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
3.81k
        product_native += (mul_left_native * -mul_right_native);
1684
3.81k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
3.81k
    }
1686
1687
    // Compute the sum of to_sub
1688
1.91k
    native sub_native(0);
1689
1.91k
    bool sub_constant = true;
1690
2.86k
    for (const auto& sub : to_sub) {
1691
2.86k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
2.86k
        sub_constant = sub_constant && sub.is_constant();
1693
2.86k
    }
1694
1695
1.91k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
1.91k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
1.91k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
1.91k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
1.91k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
1.91k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
1.91k
    std::vector<bigfield> eval_left{ result };
1714
1.91k
    std::vector<bigfield> eval_right{ divisor };
1715
3.81k
    for (const auto& in : mul_left) {
1716
3.81k
        eval_left.emplace_back(in);
1717
3.81k
    }
1718
3.81k
    for (const auto& in : mul_right) {
1719
3.81k
        eval_right.emplace_back(in);
1720
3.81k
    }
1721
1722
1.91k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
1.91k
    result.set_origin_tag(new_tag);
1725
1.91k
    return result;
1726
1.91k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
Line
Count
Source
1632
1.52k
{
1633
    // Check the basics
1634
1.52k
    ASSERT(mul_left.size() == mul_right.size());
1635
1.52k
    ASSERT(divisor.get_value() != 0);
1636
1637
1.52k
    OriginTag new_tag = divisor.get_origin_tag();
1638
3.04k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
3.04k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
3.04k
    }
1641
2.29k
    for (auto& element : to_sub) {
1642
2.29k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
2.29k
    }
1644
    // Gett he context
1645
1.52k
    Builder* ctx = divisor.context;
1646
1.52k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
1.52k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
1.52k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
1.52k
    const size_t num_multiplications = mul_left.size();
1671
1.52k
    native product_native = 0;
1672
1.52k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
1.52k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
4.57k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
3.04k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
3.04k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
3.04k
        product_native += (mul_left_native * -mul_right_native);
1684
3.04k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
3.04k
    }
1686
1687
    // Compute the sum of to_sub
1688
1.52k
    native sub_native(0);
1689
1.52k
    bool sub_constant = true;
1690
2.29k
    for (const auto& sub : to_sub) {
1691
2.29k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
2.29k
        sub_constant = sub_constant && sub.is_constant();
1693
2.29k
    }
1694
1695
1.52k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
1.52k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
1.52k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
1.52k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
1.52k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
1.52k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
1.52k
    std::vector<bigfield> eval_left{ result };
1714
1.52k
    std::vector<bigfield> eval_right{ divisor };
1715
3.04k
    for (const auto& in : mul_left) {
1716
3.04k
        eval_left.emplace_back(in);
1717
3.04k
    }
1718
3.04k
    for (const auto& in : mul_right) {
1719
3.04k
        eval_right.emplace_back(in);
1720
3.04k
    }
1721
1722
1.52k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
1.52k
    result.set_origin_tag(new_tag);
1725
1.52k
    return result;
1726
1.52k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS8_SaIS8_EESD_RKS8_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
1727
1728
template <typename Builder, typename T>
1729
bigfield<Builder, T> bigfield<Builder, T>::conditional_negate(const bool_t<Builder>& predicate) const
1730
31.0k
{
1731
31.0k
    Builder* ctx = context ? context : predicate.context;
1732
1733
31.0k
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
31.0k
    reduction_check();
1744
1745
31.0k
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
31.0k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
31.0k
    uint256_t limb_1_maximum_value =
1748
31.0k
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
31.0k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
31.0k
    uint256_t limb_2_maximum_value =
1751
31.0k
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
31.0k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
31.0k
    uint256_t limb_3_maximum_value =
1755
31.0k
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
31.0k
    uint512_t constant_to_add = modulus_u512;
1761
78.9k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
47.8k
        constant_to_add += modulus_u512;
1763
47.8k
    }
1764
1765
31.0k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
31.0k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
31.0k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
31.0k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
31.0k
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
31.0k
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
31.0k
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
31.0k
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
31.0k
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
31.0k
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
31.0k
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
31.0k
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
31.0k
    bb::fr two(2);
1784
1785
31.0k
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
31.0k
                                                                   binary_basis_limbs[0].element);
1787
31.0k
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
31.0k
                                                                   binary_basis_limbs[1].element);
1789
31.0k
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
31.0k
                                                                   binary_basis_limbs[2].element);
1791
31.0k
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
31.0k
                                                                   binary_basis_limbs[3].element);
1793
1794
31.0k
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
31.0k
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
31.0k
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
31.0k
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
31.0k
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
31.0k
                               ? binary_basis_limbs[0].maximum_value
1801
31.0k
                               : maximum_negated_limb_0;
1802
31.0k
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
31.0k
                               ? binary_basis_limbs[1].maximum_value
1804
31.0k
                               : maximum_negated_limb_1;
1805
31.0k
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
31.0k
                               ? binary_basis_limbs[2].maximum_value
1807
31.0k
                               : maximum_negated_limb_2;
1808
31.0k
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
31.0k
                               ? binary_basis_limbs[3].maximum_value
1810
31.0k
                               : maximum_negated_limb_3;
1811
1812
31.0k
    bigfield result(ctx);
1813
31.0k
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
31.0k
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
31.0k
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
31.0k
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
31.0k
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
31.0k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
31.0k
    result.prime_basis_limb =
1821
31.0k
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
31.0k
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
31.0k
    return result;
1826
31.0k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Line
Count
Source
1730
30.6k
{
1731
30.6k
    Builder* ctx = context ? context : predicate.context;
1732
1733
30.6k
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
30.6k
    reduction_check();
1744
1745
30.6k
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
30.6k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
30.6k
    uint256_t limb_1_maximum_value =
1748
30.6k
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
30.6k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
30.6k
    uint256_t limb_2_maximum_value =
1751
30.6k
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
30.6k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
30.6k
    uint256_t limb_3_maximum_value =
1755
30.6k
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
30.6k
    uint512_t constant_to_add = modulus_u512;
1761
78.1k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
47.5k
        constant_to_add += modulus_u512;
1763
47.5k
    }
1764
1765
30.6k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
30.6k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
30.6k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
30.6k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
30.6k
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
30.6k
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
30.6k
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
30.6k
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
30.6k
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
30.6k
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
30.6k
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
30.6k
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
30.6k
    bb::fr two(2);
1784
1785
30.6k
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
30.6k
                                                                   binary_basis_limbs[0].element);
1787
30.6k
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
30.6k
                                                                   binary_basis_limbs[1].element);
1789
30.6k
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
30.6k
                                                                   binary_basis_limbs[2].element);
1791
30.6k
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
30.6k
                                                                   binary_basis_limbs[3].element);
1793
1794
30.6k
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
30.6k
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
30.6k
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
30.6k
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
30.6k
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
30.6k
                               ? binary_basis_limbs[0].maximum_value
1801
30.6k
                               : maximum_negated_limb_0;
1802
30.6k
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
30.6k
                               ? binary_basis_limbs[1].maximum_value
1804
30.6k
                               : maximum_negated_limb_1;
1805
30.6k
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
30.6k
                               ? binary_basis_limbs[2].maximum_value
1807
30.6k
                               : maximum_negated_limb_2;
1808
30.6k
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
30.6k
                               ? binary_basis_limbs[3].maximum_value
1810
30.6k
                               : maximum_negated_limb_3;
1811
1812
30.6k
    bigfield result(ctx);
1813
30.6k
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
30.6k
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
30.6k
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
30.6k
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
30.6k
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
30.6k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
30.6k
    result.prime_basis_limb =
1821
30.6k
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
30.6k
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
30.6k
    return result;
1826
30.6k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_negateERKNS0_6bool_tIS6_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Line
Count
Source
1730
24
{
1731
24
    Builder* ctx = context ? context : predicate.context;
1732
1733
24
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
24
    reduction_check();
1744
1745
24
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
24
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
24
    uint256_t limb_1_maximum_value =
1748
24
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
24
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
24
    uint256_t limb_2_maximum_value =
1751
24
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
24
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
24
    uint256_t limb_3_maximum_value =
1755
24
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
24
    uint512_t constant_to_add = modulus_u512;
1761
42
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
18
        constant_to_add += modulus_u512;
1763
18
    }
1764
1765
24
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
24
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
24
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
24
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
24
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
24
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
24
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
24
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
24
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
24
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
24
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
24
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
24
    bb::fr two(2);
1784
1785
24
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
24
                                                                   binary_basis_limbs[0].element);
1787
24
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
24
                                                                   binary_basis_limbs[1].element);
1789
24
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
24
                                                                   binary_basis_limbs[2].element);
1791
24
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
24
                                                                   binary_basis_limbs[3].element);
1793
1794
24
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
24
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
24
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
24
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
24
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
24
                               ? binary_basis_limbs[0].maximum_value
1801
24
                               : maximum_negated_limb_0;
1802
24
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
24
                               ? binary_basis_limbs[1].maximum_value
1804
24
                               : maximum_negated_limb_1;
1805
24
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
24
                               ? binary_basis_limbs[2].maximum_value
1807
24
                               : maximum_negated_limb_2;
1808
24
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
24
                               ? binary_basis_limbs[3].maximum_value
1810
24
                               : maximum_negated_limb_3;
1811
1812
24
    bigfield result(ctx);
1813
24
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
24
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
24
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
24
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
24
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
24
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
24
    result.prime_basis_limb =
1821
24
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
24
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
24
    return result;
1826
24
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Line
Count
Source
1730
456
{
1731
456
    Builder* ctx = context ? context : predicate.context;
1732
1733
456
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
456
    reduction_check();
1744
1745
456
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
456
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
456
    uint256_t limb_1_maximum_value =
1748
456
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
456
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
456
    uint256_t limb_2_maximum_value =
1751
456
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
456
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
456
    uint256_t limb_3_maximum_value =
1755
456
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
456
    uint512_t constant_to_add = modulus_u512;
1761
798
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
342
        constant_to_add += modulus_u512;
1763
342
    }
1764
1765
456
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
456
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
456
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
456
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
456
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
456
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
456
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
456
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
456
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
456
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
456
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
456
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
456
    bb::fr two(2);
1784
1785
456
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
456
                                                                   binary_basis_limbs[0].element);
1787
456
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
456
                                                                   binary_basis_limbs[1].element);
1789
456
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
456
                                                                   binary_basis_limbs[2].element);
1791
456
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
456
                                                                   binary_basis_limbs[3].element);
1793
1794
456
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
456
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
456
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
456
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
456
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
456
                               ? binary_basis_limbs[0].maximum_value
1801
456
                               : maximum_negated_limb_0;
1802
456
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
456
                               ? binary_basis_limbs[1].maximum_value
1804
456
                               : maximum_negated_limb_1;
1805
456
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
456
                               ? binary_basis_limbs[2].maximum_value
1807
456
                               : maximum_negated_limb_2;
1808
456
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
456
                               ? binary_basis_limbs[3].maximum_value
1810
456
                               : maximum_negated_limb_3;
1811
1812
456
    bigfield result(ctx);
1813
456
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
456
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
456
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
456
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
456
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
456
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
456
    result.prime_basis_limb =
1821
456
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
456
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
456
    return result;
1826
456
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_negateERKNS0_6bool_tIS6_EE
1827
1828
/**
1829
 * @brief Create an element which is equal to either this or other based on the predicate
1830
 *
1831
 * @tparam Builder
1832
 * @tparam T
1833
 * @param other The other bigfield element
1834
 * @param predicate Predicate controlling the result (0 for this, 1 for the other)
1835
 * @return Resulting element
1836
 */
1837
template <typename Builder, typename T>
1838
bigfield<Builder, T> bigfield<Builder, T>::conditional_select(const bigfield& other,
1839
                                                              const bool_t<Builder>& predicate) const
1840
133k
{
1841
133k
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
182
        if (predicate.get_value()) {
1843
11
            return other;
1844
11
        }
1845
171
        return *this;
1846
182
    }
1847
133k
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
133k
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
133k
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
133k
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
133k
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
133k
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
133k
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
133k
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
133k
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
133k
    field_t prime_limb =
1859
133k
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
133k
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
133k
    result.binary_basis_limbs[0] =
1864
133k
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
133k
    result.binary_basis_limbs[1] =
1866
133k
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
133k
    result.binary_basis_limbs[2] =
1868
133k
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
133k
    result.binary_basis_limbs[3] =
1870
133k
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
133k
    result.prime_basis_limb = prime_limb;
1872
133k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
133k
    return result;
1874
133k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_selectERKS6_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
119k
{
1841
119k
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
145
        if (predicate.get_value()) {
1843
11
            return other;
1844
11
        }
1845
134
        return *this;
1846
145
    }
1847
119k
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
119k
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
119k
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
119k
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
119k
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
119k
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
119k
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
119k
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
119k
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
119k
    field_t prime_limb =
1859
119k
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
119k
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
119k
    result.binary_basis_limbs[0] =
1864
119k
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
119k
    result.binary_basis_limbs[1] =
1866
119k
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
119k
    result.binary_basis_limbs[2] =
1868
119k
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
119k
    result.binary_basis_limbs[3] =
1870
119k
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
119k
    result.prime_basis_limb = prime_limb;
1872
119k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
119k
    return result;
1874
119k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_selectERKS6_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
50
{
1841
50
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
50
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
50
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
50
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
50
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
50
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
50
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
50
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
50
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
50
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
50
    field_t prime_limb =
1859
50
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
50
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
50
    result.binary_basis_limbs[0] =
1864
50
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
50
    result.binary_basis_limbs[1] =
1866
50
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
50
    result.binary_basis_limbs[2] =
1868
50
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
50
    result.binary_basis_limbs[3] =
1870
50
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
50
    result.prime_basis_limb = prime_limb;
1872
50
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
50
    return result;
1874
50
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_selectERKS8_RKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_selectERKS7_RKNS0_6bool_tIS6_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
669
{
1841
669
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
3
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
3
        return *this;
1846
3
    }
1847
666
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
666
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
666
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
666
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
666
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
666
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
666
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
666
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
666
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
666
    field_t prime_limb =
1859
666
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
666
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
666
    result.binary_basis_limbs[0] =
1864
666
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
666
    result.binary_basis_limbs[1] =
1866
666
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
666
    result.binary_basis_limbs[2] =
1868
666
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
666
    result.binary_basis_limbs[3] =
1870
666
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
666
    result.prime_basis_limb = prime_limb;
1872
666
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
666
    return result;
1874
669
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
Line
Count
Source
1840
12.8k
{
1841
12.8k
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
12.8k
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
12.8k
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
12.8k
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
12.8k
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
12.8k
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
12.8k
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
12.8k
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
12.8k
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
12.8k
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
12.8k
    field_t prime_limb =
1859
12.8k
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
12.8k
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
12.8k
    result.binary_basis_limbs[0] =
1864
12.8k
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
12.8k
    result.binary_basis_limbs[1] =
1866
12.8k
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
12.8k
    result.binary_basis_limbs[2] =
1868
12.8k
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
12.8k
    result.binary_basis_limbs[3] =
1870
12.8k
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
12.8k
    result.prime_basis_limb = prime_limb;
1872
12.8k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
12.8k
    return result;
1874
12.8k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
199
{
1841
199
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
18
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
18
        return *this;
1846
18
    }
1847
181
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
181
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
181
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
181
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
181
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
181
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
181
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
181
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
181
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
181
    field_t prime_limb =
1859
181
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
181
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
181
    result.binary_basis_limbs[0] =
1864
181
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
181
    result.binary_basis_limbs[1] =
1866
181
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
181
    result.binary_basis_limbs[2] =
1868
181
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
181
    result.binary_basis_limbs[3] =
1870
181
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
181
    result.prime_basis_limb = prime_limb;
1872
181
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
181
    return result;
1874
199
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
10
{
1841
10
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
10
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
10
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
10
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
10
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
10
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
10
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
10
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
10
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
10
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
10
    field_t prime_limb =
1859
10
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
10
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
10
    result.binary_basis_limbs[0] =
1864
10
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
10
    result.binary_basis_limbs[1] =
1866
10
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
10
    result.binary_basis_limbs[2] =
1868
10
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
10
    result.binary_basis_limbs[3] =
1870
10
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
10
    result.prime_basis_limb = prime_limb;
1872
10
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
10
    return result;
1874
10
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
Line
Count
Source
1840
156
{
1841
156
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
16
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
16
        return *this;
1846
16
    }
1847
140
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
140
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
140
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
140
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
140
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
140
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
140
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
140
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
140
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
140
    field_t prime_limb =
1859
140
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
140
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
140
    result.binary_basis_limbs[0] =
1864
140
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
140
    result.binary_basis_limbs[1] =
1866
140
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
140
    result.binary_basis_limbs[2] =
1868
140
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
140
    result.binary_basis_limbs[3] =
1870
140
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
140
    result.prime_basis_limb = prime_limb;
1872
140
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
140
    return result;
1874
156
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
Line
Count
Source
1840
8
{
1841
8
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
8
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
8
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
8
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
8
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
8
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
8
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
8
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
8
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
8
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
8
    field_t prime_limb =
1859
8
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
8
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
8
    result.binary_basis_limbs[0] =
1864
8
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
8
    result.binary_basis_limbs[1] =
1866
8
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
8
    result.binary_basis_limbs[2] =
1868
8
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
8
    result.binary_basis_limbs[3] =
1870
8
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
8
    result.prime_basis_limb = prime_limb;
1872
8
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
8
    return result;
1874
8
}
1875
1876
/**
1877
 * @brief Validate whether two bigfield elements are equal to each other
1878
 * @details To evaluate whether `(a == b)`, we use result boolean `r` to evaluate the following logic:
1879
 *          (n.b all algebra involving bigfield elements is done in the bigfield)
1880
 *              1. If `r == 1` , `a - b == 0`
1881
 *              2. If `r == 0`, `a - b` posesses an inverse `I` i.e. `(a - b) * I - 1 == 0`
1882
 *          We efficiently evaluate this logic by evaluating a single expression `(a - b)*X = Y`
1883
 *          We use conditional assignment logic to define `X, Y` to be the following:
1884
 *              If `r == 1` then `X = 1, Y = 0`
1885
 *              If `r == 0` then `X = I, Y = 1`
1886
 *          This allows us to evaluate `operator==` using only 1 bigfield multiplication operation.
1887
 *          We can check the product equals 0 or 1 by directly evaluating the binary basis/prime basis limbs of Y.
1888
 *          i.e. if `r == 1` then `(a - b)*X` should have 0 for all limb values
1889
 *               if `r == 0` then `(a - b)*X` should have 1 in the least significant binary basis limb and 0
1890
 * elsewhere
1891
 * @tparam Builder
1892
 * @tparam T
1893
 * @param other
1894
 * @return bool_t<Builder>
1895
 */
1896
template <typename Builder, typename T> bool_t<Builder> bigfield<Builder, T>::operator==(const bigfield& other) const
1897
23.5k
{
1898
23.5k
    Builder* ctx = context ? context : other.get_context();
1899
23.5k
    auto lhs = get_value() % modulus_u512;
1900
23.5k
    auto rhs = other.get_value() % modulus_u512;
1901
23.5k
    bool is_equal_raw = (lhs == rhs);
1902
23.5k
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
23.5k
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
23.5k
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
23.5k
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
23.5k
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
23.5k
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
23.5k
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
23.5k
    bigfield product = diff * multiplicand;
1922
1923
23.5k
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
23.5k
    product.prime_basis_limb.assert_equal(result);
1926
23.5k
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
23.5k
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
23.5k
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
23.5k
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
23.5k
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
23.5k
    return is_equal;
1932
23.5k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEeqERKS6_
Line
Count
Source
1897
20.8k
{
1898
20.8k
    Builder* ctx = context ? context : other.get_context();
1899
20.8k
    auto lhs = get_value() % modulus_u512;
1900
20.8k
    auto rhs = other.get_value() % modulus_u512;
1901
20.8k
    bool is_equal_raw = (lhs == rhs);
1902
20.8k
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
20.8k
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
20.8k
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
20.8k
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
20.8k
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
20.8k
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
20.8k
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
20.8k
    bigfield product = diff * multiplicand;
1922
1923
20.8k
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
20.8k
    product.prime_basis_limb.assert_equal(result);
1926
20.8k
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
20.8k
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
20.8k
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
20.8k
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
20.8k
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
20.8k
    return is_equal;
1932
20.8k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEeqERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEeqERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EeqERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEeqERKS7_
Line
Count
Source
1897
132
{
1898
132
    Builder* ctx = context ? context : other.get_context();
1899
132
    auto lhs = get_value() % modulus_u512;
1900
132
    auto rhs = other.get_value() % modulus_u512;
1901
132
    bool is_equal_raw = (lhs == rhs);
1902
132
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
132
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
132
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
132
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
132
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
132
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
132
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
132
    bigfield product = diff * multiplicand;
1922
1923
132
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
132
    product.prime_basis_limb.assert_equal(result);
1926
132
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
132
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
132
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
132
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
132
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
132
    return is_equal;
1932
132
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEeqERKS7_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEeqERKS9_
Line
Count
Source
1897
2.50k
{
1898
2.50k
    Builder* ctx = context ? context : other.get_context();
1899
2.50k
    auto lhs = get_value() % modulus_u512;
1900
2.50k
    auto rhs = other.get_value() % modulus_u512;
1901
2.50k
    bool is_equal_raw = (lhs == rhs);
1902
2.50k
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
2.50k
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
2.50k
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
2.50k
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
2.50k
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
2.50k
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
2.50k
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
2.50k
    bigfield product = diff * multiplicand;
1922
1923
2.50k
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
2.50k
    product.prime_basis_limb.assert_equal(result);
1926
2.50k
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
2.50k
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
2.50k
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
2.50k
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
2.50k
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
2.50k
    return is_equal;
1932
2.50k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEeqERKS9_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEeqERKS7_
Line
Count
Source
1897
30
{
1898
30
    Builder* ctx = context ? context : other.get_context();
1899
30
    auto lhs = get_value() % modulus_u512;
1900
30
    auto rhs = other.get_value() % modulus_u512;
1901
30
    bool is_equal_raw = (lhs == rhs);
1902
30
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
30
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
30
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
30
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
30
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
30
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
30
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
30
    bigfield product = diff * multiplicand;
1922
1923
30
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
30
    product.prime_basis_limb.assert_equal(result);
1926
30
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
30
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
30
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
30
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
30
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
30
    return is_equal;
1932
30
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEeqERKS7_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEeqERKS9_
Line
Count
Source
1897
24
{
1898
24
    Builder* ctx = context ? context : other.get_context();
1899
24
    auto lhs = get_value() % modulus_u512;
1900
24
    auto rhs = other.get_value() % modulus_u512;
1901
24
    bool is_equal_raw = (lhs == rhs);
1902
24
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
24
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
24
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
24
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
24
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
24
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
24
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
24
    bigfield product = diff * multiplicand;
1922
1923
24
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
24
    product.prime_basis_limb.assert_equal(result);
1926
24
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
24
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
24
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
24
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
24
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
24
    return is_equal;
1932
24
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEeqERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEeqERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEeqERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEeqERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EeqERKS7_
1933
1934
/**
1935
 * REDUCTION CHECK
1936
 *
1937
 * When performing bigfield operations, we need to ensure the maximum value is less than:
1938
 *      sqrt(2^{272} * native_modulus)
1939
 *
1940
 * We also need to ensure each binary basis limb is less than the maximum limb value
1941
 *
1942
 * This prevents our field arithmetic from overflowing the native modulus boundary, whilst ensuring we can
1943
 * still use the chinese remainder theorem to validate field multiplications with a reduced number of range checks
1944
 *
1945
 **/
1946
template <typename Builder, typename T> void bigfield<Builder, T>::reduction_check() const
1947
8.49M
{
1948
1949
8.49M
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
1.01M
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
1.01M
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
1.01M
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
1.01M
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
1.01M
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
1.01M
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
1.01M
                                               prime_basis_limb.get_origin_tag() });
1959
1.01M
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
1.01M
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
1.01M
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
1.01M
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
1.01M
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
1.01M
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
1.01M
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
1.01M
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
1.01M
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
1.01M
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
1.01M
        return;
1971
1.01M
    }
1972
1973
7.48M
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
7.48M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
7.48M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
7.48M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
7.48M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
7.48M
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
7.48M
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
81
        self_reduce();
1981
81
    }
1982
7.48M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE15reduction_checkEv
Line
Count
Source
1947
7.74M
{
1948
1949
7.74M
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
922k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
922k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
922k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
922k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
922k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
922k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
922k
                                               prime_basis_limb.get_origin_tag() });
1959
922k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
922k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
922k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
922k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
922k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
922k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
922k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
922k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
922k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
922k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
922k
        return;
1971
922k
    }
1972
1973
6.82M
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
6.82M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
6.82M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
6.82M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
6.82M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
6.82M
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
6.82M
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
75
        self_reduce();
1981
75
    }
1982
6.82M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE15reduction_checkEv
Line
Count
Source
1947
1.46k
{
1948
1949
1.46k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
56
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
56
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
56
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
56
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
56
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
56
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
56
                                               prime_basis_limb.get_origin_tag() });
1959
56
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
56
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
56
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
56
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
56
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
56
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
56
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
56
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
56
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
56
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
56
        return;
1971
56
    }
1972
1973
1.40k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
1.40k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
1.40k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
1.40k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
1.40k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
1.40k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
1.40k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
6
        self_reduce();
1981
6
    }
1982
1.40k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE15reduction_checkEv
Line
Count
Source
1947
40
{
1948
1949
40
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
8
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
8
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
8
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
8
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
8
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
8
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
8
                                               prime_basis_limb.get_origin_tag() });
1959
8
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
8
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
8
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
8
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
8
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
8
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
8
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
8
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
8
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
8
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
8
        return;
1971
8
    }
1972
1973
32
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
32
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
32
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
32
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
32
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
32
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
32
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
32
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E15reduction_checkEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
34.7k
{
1948
1949
34.7k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
4.11k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
4.11k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
4.11k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
4.11k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
4.11k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
4.11k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
4.11k
                                               prime_basis_limb.get_origin_tag() });
1959
4.11k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
4.11k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
4.11k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
4.11k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
4.11k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
4.11k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
4.11k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
4.11k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
4.11k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
4.11k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
4.11k
        return;
1971
4.11k
    }
1972
1973
30.5k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
30.5k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
30.5k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
30.5k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
30.5k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
30.5k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
30.5k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
30.5k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
216
{
1948
1949
216
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
36
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
36
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
36
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
36
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
36
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
36
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
36
                                               prime_basis_limb.get_origin_tag() });
1959
36
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
36
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
36
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
36
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
36
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
36
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
36
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
36
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
36
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
36
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
36
        return;
1971
36
    }
1972
1973
180
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
180
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
180
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
180
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
180
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
180
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
180
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
180
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
604k
{
1948
1949
604k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
72.2k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
72.2k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
72.2k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
72.2k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
72.2k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
72.2k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
72.2k
                                               prime_basis_limb.get_origin_tag() });
1959
72.2k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
72.2k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
72.2k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
72.2k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
72.2k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
72.2k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
72.2k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
72.2k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
72.2k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
72.2k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
72.2k
        return;
1971
72.2k
    }
1972
1973
532k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
532k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
532k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
532k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
532k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
532k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
532k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
532k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
3.87k
{
1948
1949
3.87k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
684
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
684
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
684
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
684
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
684
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
684
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
684
                                               prime_basis_limb.get_origin_tag() });
1959
684
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
684
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
684
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
684
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
684
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
684
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
684
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
684
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
684
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
684
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
684
        return;
1971
684
    }
1972
1973
3.19k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
3.19k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
3.19k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
3.19k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
3.19k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
3.19k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
3.19k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
3.19k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
56.4k
{
1948
1949
56.4k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
6.05k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
6.05k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
6.05k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
6.05k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
6.05k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
6.05k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
6.05k
                                               prime_basis_limb.get_origin_tag() });
1959
6.05k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
6.05k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
6.05k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
6.05k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
6.05k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
6.05k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
6.05k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
6.05k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
6.05k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
6.05k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
6.05k
        return;
1971
6.05k
    }
1972
1973
50.3k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
50.3k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
50.3k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
50.3k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
50.3k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
50.3k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
50.3k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
50.3k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
60
{
1948
1949
60
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
0
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
0
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
0
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
0
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
0
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
0
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
0
                                               prime_basis_limb.get_origin_tag() });
1959
0
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
0
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
0
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
0
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
0
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
0
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
0
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
0
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
0
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
0
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
0
        return;
1971
0
    }
1972
1973
60
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
60
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
60
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
60
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
60
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
60
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
60
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
60
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
45.1k
{
1948
1949
45.1k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
4.84k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
4.84k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
4.84k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
4.84k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
4.84k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
4.84k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
4.84k
                                               prime_basis_limb.get_origin_tag() });
1959
4.84k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
4.84k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
4.84k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
4.84k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
4.84k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
4.84k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
4.84k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
4.84k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
4.84k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
4.84k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
4.84k
        return;
1971
4.84k
    }
1972
1973
40.3k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
40.3k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
40.3k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
40.3k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
40.3k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
40.3k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
40.3k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
40.3k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
48
{
1948
1949
48
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
0
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
0
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
0
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
0
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
0
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
0
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
0
                                               prime_basis_limb.get_origin_tag() });
1959
0
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
0
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
0
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
0
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
0
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
0
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
0
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
0
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
0
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
0
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
0
        return;
1971
0
    }
1972
1973
48
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
48
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
48
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
48
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
48
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
48
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
48
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
48
}
1983
1984
/**
1985
 * SANITY CHECK on a value that is about to interact with another value
1986
 *
1987
 * @details ASSERTs that the value of all limbs is less than or equal to the prohibited maximum value. Checks that the
1988
 *maximum value of the whole element is also less than a prohibited maximum value
1989
 *
1990
 **/
1991
template <typename Builder, typename T> void bigfield<Builder, T>::sanity_check() const
1992
6.60M
{
1993
1994
6.60M
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
6.60M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
6.60M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
6.60M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
6.60M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
6.60M
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
6.60M
             limb_overflow_test_2 || limb_overflow_test_3));
2001
6.60M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12sanity_checkEv
Line
Count
Source
1992
6.06M
{
1993
1994
6.06M
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
6.06M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
6.06M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
6.06M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
6.06M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
6.06M
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
6.06M
             limb_overflow_test_2 || limb_overflow_test_3));
2001
6.06M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12sanity_checkEv
Line
Count
Source
1992
1.51k
{
1993
1994
1.51k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
1.51k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
1.51k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
1.51k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
1.51k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
1.51k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
1.51k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
1.51k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12sanity_checkEv
Line
Count
Source
1992
64
{
1993
1994
64
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
64
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
64
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
64
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
64
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
64
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
64
             limb_overflow_test_2 || limb_overflow_test_3));
2001
64
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12sanity_checkEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
24.9k
{
1993
1994
24.9k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
24.9k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
24.9k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
24.9k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
24.9k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
24.9k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
24.9k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
24.9k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
278
{
1993
1994
278
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
278
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
278
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
278
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
278
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
278
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
278
             limb_overflow_test_2 || limb_overflow_test_3));
2001
278
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
431k
{
1993
1994
431k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
431k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
431k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
431k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
431k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
431k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
431k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
431k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
4.10k
{
1993
1994
4.10k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
4.10k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
4.10k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
4.10k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
4.10k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
4.10k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
4.10k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
4.10k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
40.9k
{
1993
1994
40.9k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
40.9k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
40.9k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
40.9k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
40.9k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
40.9k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
40.9k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
40.9k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
170
{
1993
1994
170
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
170
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
170
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
170
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
170
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
170
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
170
             limb_overflow_test_2 || limb_overflow_test_3));
2001
170
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
32.7k
{
1993
1994
32.7k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
32.7k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
32.7k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
32.7k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
32.7k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
32.7k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
32.7k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
32.7k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
136
{
1993
1994
136
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
136
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
136
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
136
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
136
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
136
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
136
             limb_overflow_test_2 || limb_overflow_test_3));
2001
136
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12sanity_checkEv
2002
2003
// Underneath performs assert_less_than(modulus)
2004
// create a version with mod 2^t element part in [0,p-1]
2005
// After reducing to size 2^s, we check (p-1)-a is non-negative as integer.
2006
// We perform subtraction using carries on blocks of size 2^b. The operations inside the blocks are done mod r
2007
// Including the effect of carries the operation inside each limb is in the range [-2^b-1,2^{b+1}]
2008
// Assuming this values are all distinct mod r, which happens e.g. if r/2>2^{b+1}, then if all limb values are
2009
// non-negative at the end of subtraction, we know the subtraction result is positive as integers and a<p
2010
template <typename Builder, typename T> void bigfield<Builder, T>::assert_is_in_field() const
2011
439
{
2012
439
    assert_less_than(modulus);
2013
439
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
16
{
2012
16
    assert_less_than(modulus);
2013
16
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
3
{
2012
3
    assert_less_than(modulus);
2013
3
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18assert_is_in_fieldEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18assert_is_in_fieldEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
11
{
2012
11
    assert_less_than(modulus);
2013
11
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
24
{
2012
24
    assert_less_than(modulus);
2013
24
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18assert_is_in_fieldEv
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
342
{
2012
342
    assert_less_than(modulus);
2013
342
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
8
{
2012
8
    assert_less_than(modulus);
2013
8
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
15
{
2012
15
    assert_less_than(modulus);
2013
15
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
8
{
2012
8
    assert_less_than(modulus);
2013
8
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
12
{
2012
12
    assert_less_than(modulus);
2013
12
}
2014
2015
template <typename Builder, typename T> void bigfield<Builder, T>::assert_less_than(const uint256_t upper_limit) const
2016
580
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
580
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
580
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
0
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
0
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
0
    uint256_t value = get_value().lo;
2031
2032
0
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
0
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
0
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
0
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
0
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
0
    bool borrow_1_value =
2039
0
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
0
    bool borrow_2_value =
2041
0
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
0
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
0
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
0
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
0
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
0
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
0
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
0
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
0
    field_t<Builder> r0 =
2056
0
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
0
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
0
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
0
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
0
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
0
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
0
    r0 = r0.normalize();
2063
0
    r1 = r1.normalize();
2064
0
    r2 = r2.normalize();
2065
0
    r3 = r3.normalize();
2066
580
    if constexpr (HasPlookup<Builder>) {
2067
580
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
580
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
580
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
580
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
580
    } else {
2072
0
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
0
                                                   "bigfield: assert_less_than range constraint 1.");
2075
0
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
0
                                                   "bigfield: assert_less_than range constraint 2.");
2078
0
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
0
                                                   "bigfield: assert_less_than range constraint 3.");
2081
0
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
0
                                                   "bigfield: assert_less_than range constraint 4.");
2084
0
    }
2085
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
28
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
28
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
28
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
28
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
28
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
28
    uint256_t value = get_value().lo;
2031
2032
28
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
28
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
28
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
28
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
28
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
28
    bool borrow_1_value =
2039
28
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
28
    bool borrow_2_value =
2041
28
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
28
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
28
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
28
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
28
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
28
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
28
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
28
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
28
    field_t<Builder> r0 =
2056
28
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
28
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
28
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
28
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
28
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
28
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
28
    r0 = r0.normalize();
2063
28
    r1 = r1.normalize();
2064
28
    r2 = r2.normalize();
2065
28
    r3 = r3.normalize();
2066
28
    if constexpr (HasPlookup<Builder>) {
2067
28
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
28
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
28
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
28
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
28
    } else {
2072
28
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
28
                                                   "bigfield: assert_less_than range constraint 1.");
2075
28
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
28
                                                   "bigfield: assert_less_than range constraint 2.");
2078
28
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
28
                                                   "bigfield: assert_less_than range constraint 3.");
2081
28
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
28
                                                   "bigfield: assert_less_than range constraint 4.");
2084
28
    }
2085
28
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
3
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
3
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
3
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
3
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
3
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
3
    uint256_t value = get_value().lo;
2031
2032
3
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
3
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
3
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
3
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
3
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
3
    bool borrow_1_value =
2039
3
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
3
    bool borrow_2_value =
2041
3
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
3
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
3
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
3
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
3
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
3
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
3
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
3
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
3
    field_t<Builder> r0 =
2056
3
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
3
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
3
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
3
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
3
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
3
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
3
    r0 = r0.normalize();
2063
3
    r1 = r1.normalize();
2064
3
    r2 = r2.normalize();
2065
3
    r3 = r3.normalize();
2066
3
    if constexpr (HasPlookup<Builder>) {
2067
3
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
3
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
3
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
3
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
3
    } else {
2072
3
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
3
                                                   "bigfield: assert_less_than range constraint 1.");
2075
3
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
3
                                                   "bigfield: assert_less_than range constraint 2.");
2078
3
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
3
                                                   "bigfield: assert_less_than range constraint 3.");
2081
3
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
3
                                                   "bigfield: assert_less_than range constraint 4.");
2084
3
    }
2085
3
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E16assert_less_thanENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
11
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
11
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
11
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
11
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
11
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
11
    uint256_t value = get_value().lo;
2031
2032
11
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
11
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
11
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
11
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
11
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
11
    bool borrow_1_value =
2039
11
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
11
    bool borrow_2_value =
2041
11
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
11
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
11
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
11
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
11
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
11
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
11
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
11
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
11
    field_t<Builder> r0 =
2056
11
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
11
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
11
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
11
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
11
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
11
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
11
    r0 = r0.normalize();
2063
11
    r1 = r1.normalize();
2064
11
    r2 = r2.normalize();
2065
11
    r3 = r3.normalize();
2066
11
    if constexpr (HasPlookup<Builder>) {
2067
11
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
11
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
11
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
11
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
11
    } else {
2072
11
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
11
                                                   "bigfield: assert_less_than range constraint 1.");
2075
11
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
11
                                                   "bigfield: assert_less_than range constraint 2.");
2078
11
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
11
                                                   "bigfield: assert_less_than range constraint 3.");
2081
11
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
11
                                                   "bigfield: assert_less_than range constraint 4.");
2084
11
    }
2085
11
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
30
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
30
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
30
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
30
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
30
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
30
    uint256_t value = get_value().lo;
2031
2032
30
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
30
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
30
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
30
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
30
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
30
    bool borrow_1_value =
2039
30
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
30
    bool borrow_2_value =
2041
30
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
30
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
30
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
30
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
30
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
30
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
30
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
30
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
30
    field_t<Builder> r0 =
2056
30
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
30
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
30
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
30
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
30
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
30
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
30
    r0 = r0.normalize();
2063
30
    r1 = r1.normalize();
2064
30
    r2 = r2.normalize();
2065
30
    r3 = r3.normalize();
2066
30
    if constexpr (HasPlookup<Builder>) {
2067
30
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
30
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
30
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
30
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
30
    } else {
2072
30
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
30
                                                   "bigfield: assert_less_than range constraint 1.");
2075
30
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
30
                                                   "bigfield: assert_less_than range constraint 2.");
2078
30
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
30
                                                   "bigfield: assert_less_than range constraint 3.");
2081
30
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
30
                                                   "bigfield: assert_less_than range constraint 4.");
2084
30
    }
2085
30
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
456
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
456
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
456
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
456
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
456
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
456
    uint256_t value = get_value().lo;
2031
2032
456
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
456
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
456
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
456
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
456
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
456
    bool borrow_1_value =
2039
456
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
456
    bool borrow_2_value =
2041
456
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
456
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
456
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
456
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
456
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
456
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
456
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
456
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
456
    field_t<Builder> r0 =
2056
456
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
456
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
456
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
456
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
456
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
456
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
456
    r0 = r0.normalize();
2063
456
    r1 = r1.normalize();
2064
456
    r2 = r2.normalize();
2065
456
    r3 = r3.normalize();
2066
456
    if constexpr (HasPlookup<Builder>) {
2067
456
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
456
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
456
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
456
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
456
    } else {
2072
456
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
456
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
456
                                                   "bigfield: assert_less_than range constraint 1.");
2075
456
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
456
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
456
                                                   "bigfield: assert_less_than range constraint 2.");
2078
456
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
456
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
456
                                                   "bigfield: assert_less_than range constraint 3.");
2081
456
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
456
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
456
                                                   "bigfield: assert_less_than range constraint 4.");
2084
456
    }
2085
456
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
8
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
8
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
8
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
8
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
8
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
8
    uint256_t value = get_value().lo;
2031
2032
8
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
8
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
8
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
8
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
8
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
8
    bool borrow_1_value =
2039
8
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
8
    bool borrow_2_value =
2041
8
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
8
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
8
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
8
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
8
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
8
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
8
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
8
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
8
    field_t<Builder> r0 =
2056
8
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
8
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
8
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
8
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
8
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
8
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
8
    r0 = r0.normalize();
2063
8
    r1 = r1.normalize();
2064
8
    r2 = r2.normalize();
2065
8
    r3 = r3.normalize();
2066
8
    if constexpr (HasPlookup<Builder>) {
2067
8
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
8
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
8
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
8
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
8
    } else {
2072
8
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
8
                                                   "bigfield: assert_less_than range constraint 1.");
2075
8
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
8
                                                   "bigfield: assert_less_than range constraint 2.");
2078
8
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
8
                                                   "bigfield: assert_less_than range constraint 3.");
2081
8
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
8
                                                   "bigfield: assert_less_than range constraint 4.");
2084
8
    }
2085
8
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
20
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
20
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
20
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
20
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
20
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
20
    uint256_t value = get_value().lo;
2031
2032
20
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
20
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
20
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
20
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
20
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
20
    bool borrow_1_value =
2039
20
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
20
    bool borrow_2_value =
2041
20
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
20
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
20
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
20
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
20
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
20
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
20
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
20
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
20
    field_t<Builder> r0 =
2056
20
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
20
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
20
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
20
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
20
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
20
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
20
    r0 = r0.normalize();
2063
20
    r1 = r1.normalize();
2064
20
    r2 = r2.normalize();
2065
20
    r3 = r3.normalize();
2066
20
    if constexpr (HasPlookup<Builder>) {
2067
20
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
20
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
20
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
20
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
20
    } else {
2072
20
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
20
                                                   "bigfield: assert_less_than range constraint 1.");
2075
20
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
20
                                                   "bigfield: assert_less_than range constraint 2.");
2078
20
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
20
                                                   "bigfield: assert_less_than range constraint 3.");
2081
20
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
20
                                                   "bigfield: assert_less_than range constraint 4.");
2084
20
    }
2085
20
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
8
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
8
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
8
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
8
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
8
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
8
    uint256_t value = get_value().lo;
2031
2032
8
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
8
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
8
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
8
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
8
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
8
    bool borrow_1_value =
2039
8
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
8
    bool borrow_2_value =
2041
8
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
8
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
8
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
8
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
8
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
8
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
8
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
8
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
8
    field_t<Builder> r0 =
2056
8
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
8
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
8
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
8
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
8
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
8
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
8
    r0 = r0.normalize();
2063
8
    r1 = r1.normalize();
2064
8
    r2 = r2.normalize();
2065
8
    r3 = r3.normalize();
2066
8
    if constexpr (HasPlookup<Builder>) {
2067
8
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
8
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
8
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
8
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
8
    } else {
2072
8
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
8
                                                   "bigfield: assert_less_than range constraint 1.");
2075
8
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
8
                                                   "bigfield: assert_less_than range constraint 2.");
2078
8
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
8
                                                   "bigfield: assert_less_than range constraint 3.");
2081
8
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
8
                                                   "bigfield: assert_less_than range constraint 4.");
2084
8
    }
2085
8
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
16
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
16
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
16
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
16
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
16
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
16
    uint256_t value = get_value().lo;
2031
2032
16
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
16
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
16
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
16
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
16
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
16
    bool borrow_1_value =
2039
16
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
16
    bool borrow_2_value =
2041
16
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
16
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
16
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
16
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
16
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
16
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
16
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
16
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
16
    field_t<Builder> r0 =
2056
16
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
16
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
16
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
16
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
16
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
16
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
16
    r0 = r0.normalize();
2063
16
    r1 = r1.normalize();
2064
16
    r2 = r2.normalize();
2065
16
    r3 = r3.normalize();
2066
16
    if constexpr (HasPlookup<Builder>) {
2067
16
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
16
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
16
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
16
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
16
    } else {
2072
16
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
16
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
16
                                                   "bigfield: assert_less_than range constraint 1.");
2075
16
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
16
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
16
                                                   "bigfield: assert_less_than range constraint 2.");
2078
16
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
16
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
16
                                                   "bigfield: assert_less_than range constraint 3.");
2081
16
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
16
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
16
                                                   "bigfield: assert_less_than range constraint 4.");
2084
16
    }
2085
16
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E16assert_less_thanENS_7numeric9uint256_tE
2086
2087
// check elements are equal mod p by proving their integer difference is a multiple of p.
2088
// This relies on the minus operator for a-b increasing a by a multiple of p large enough so diff is non-negative
2089
// When one of the elements is a constant and another is a witness we check equality of limbs, so if the witness
2090
// bigfield element is in an unreduced form, it needs to be reduced first. We don't have automatice reduced form
2091
// detection for now, so it is up to the circuit writer to detect this
2092
template <typename Builder, typename T> void bigfield<Builder, T>::assert_equal(const bigfield& other) const
2093
476
{
2094
476
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
476
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
476
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
30
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
30
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
30
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
30
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
30
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
30
        t0.assert_is_zero();
2110
30
        t1.assert_is_zero();
2111
30
        t2.assert_is_zero();
2112
30
        t3.assert_is_zero();
2113
30
        t4.assert_is_zero();
2114
30
        return;
2115
446
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
446
    } else {
2119
2120
446
        bigfield diff = *this - other;
2121
446
        const uint512_t diff_val = diff.get_value();
2122
446
        const uint512_t modulus(target_basis.modulus);
2123
2124
446
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
446
        if (remainder_512 != 0) {
2126
9
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
9
        }
2128
446
        bigfield quotient;
2129
2130
446
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
446
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
446
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
446
                            false,
2134
446
                            num_quotient_bits);
2135
446
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
446
    }
2137
476
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12assert_equalERKS6_
Line
Count
Source
2093
136
{
2094
136
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
136
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
136
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
30
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
30
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
30
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
30
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
30
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
30
        t0.assert_is_zero();
2110
30
        t1.assert_is_zero();
2111
30
        t2.assert_is_zero();
2112
30
        t3.assert_is_zero();
2113
30
        t4.assert_is_zero();
2114
30
        return;
2115
106
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
106
    } else {
2119
2120
106
        bigfield diff = *this - other;
2121
106
        const uint512_t diff_val = diff.get_value();
2122
106
        const uint512_t modulus(target_basis.modulus);
2123
2124
106
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
106
        if (remainder_512 != 0) {
2126
9
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
9
        }
2128
106
        bigfield quotient;
2129
2130
106
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
106
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
106
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
106
                            false,
2134
106
                            num_quotient_bits);
2135
106
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
106
    }
2137
136
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12assert_equalERKS6_
Line
Count
Source
2093
322
{
2094
322
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
322
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
322
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
0
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
0
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
0
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
0
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
0
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
0
        t0.assert_is_zero();
2110
0
        t1.assert_is_zero();
2111
0
        t2.assert_is_zero();
2112
0
        t3.assert_is_zero();
2113
0
        t4.assert_is_zero();
2114
0
        return;
2115
322
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
322
    } else {
2119
2120
322
        bigfield diff = *this - other;
2121
322
        const uint512_t diff_val = diff.get_value();
2122
322
        const uint512_t modulus(target_basis.modulus);
2123
2124
322
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
322
        if (remainder_512 != 0) {
2126
0
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
0
        }
2128
322
        bigfield quotient;
2129
2130
322
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
322
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
322
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
322
                            false,
2134
322
                            num_quotient_bits);
2135
322
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
322
    }
2137
322
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12assert_equalERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12assert_equalERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12assert_equalERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12assert_equalERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12assert_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12assert_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12assert_equalERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12assert_equalERKS7_
Line
Count
Source
2093
10
{
2094
10
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
10
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
10
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
0
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
0
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
0
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
0
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
0
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
0
        t0.assert_is_zero();
2110
0
        t1.assert_is_zero();
2111
0
        t2.assert_is_zero();
2112
0
        t3.assert_is_zero();
2113
0
        t4.assert_is_zero();
2114
0
        return;
2115
10
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
10
    } else {
2119
2120
10
        bigfield diff = *this - other;
2121
10
        const uint512_t diff_val = diff.get_value();
2122
10
        const uint512_t modulus(target_basis.modulus);
2123
2124
10
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
10
        if (remainder_512 != 0) {
2126
0
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
0
        }
2128
10
        bigfield quotient;
2129
2130
10
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
10
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
10
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
10
                            false,
2134
10
                            num_quotient_bits);
2135
10
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
10
    }
2137
10
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12assert_equalERKS9_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12assert_equalERKS9_
Line
Count
Source
2093
8
{
2094
8
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
8
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
8
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
0
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
0
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
0
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
0
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
0
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
0
        t0.assert_is_zero();
2110
0
        t1.assert_is_zero();
2111
0
        t2.assert_is_zero();
2112
0
        t3.assert_is_zero();
2113
0
        t4.assert_is_zero();
2114
0
        return;
2115
8
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
8
    } else {
2119
2120
8
        bigfield diff = *this - other;
2121
8
        const uint512_t diff_val = diff.get_value();
2122
8
        const uint512_t modulus(target_basis.modulus);
2123
2124
8
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
8
        if (remainder_512 != 0) {
2126
0
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
0
        }
2128
8
        bigfield quotient;
2129
2130
8
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
8
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
8
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
8
                            false,
2134
8
                            num_quotient_bits);
2135
8
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
8
    }
2137
8
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12assert_equalERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12assert_equalERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12assert_equalERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12assert_equalERKS7_
2138
2139
// construct a proof that points are different mod p, when they are different mod r
2140
// WARNING: This method doesn't have perfect completeness - for points equal mod r (or with certain difference kp
2141
// mod r) but different mod p, you can't construct a proof. The chances of an honest prover running afoul of this
2142
// condition are extremely small (TODO: compute probability) Note also that the number of constraints depends on how
2143
// much the values have overflown beyond p e.g. due to an addition chain The function is based on the following.
2144
// Suppose a-b = 0 mod p. Then a-b = k*p for k in a range [-R,L] such that L*p>= a, R*p>=b. And also a-b = k*p mod r
2145
// for such k. Thus we can verify a-b is non-zero mod p by taking the product of such values (a-b-kp) and showing
2146
// it's non-zero mod r
2147
template <typename Builder, typename T> void bigfield<Builder, T>::assert_is_not_equal(const bigfield& other) const
2148
305k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
610k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
610k
        uint512_t target = target_modulus;
2152
610k
        size_t overload_count = 0;
2153
1.22M
        while (target <= maximum_value) {
2154
610k
            ++overload_count;
2155
610k
            target += target_modulus;
2156
610k
        }
2157
610k
        return overload_count;
2158
610k
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS6_ENKUlRKNS_7numeric5uintxINS9_9uint256_tEEEE_clESE_
Line
Count
Source
2150
581k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
581k
        uint512_t target = target_modulus;
2152
581k
        size_t overload_count = 0;
2153
1.16M
        while (target <= maximum_value) {
2154
581k
            ++overload_count;
2155
581k
            target += target_modulus;
2156
581k
        }
2157
581k
        return overload_count;
2158
581k
    };
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE19assert_is_not_equalERKS6_ENKUlRKNS_7numeric5uintxINS9_9uint256_tEEEE_clESE_
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS8_ENKUlRKNS_7numeric5uintxINSB_9uint256_tEEEE_clESG_
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
1.22k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
1.22k
        uint512_t target = target_modulus;
2152
1.22k
        size_t overload_count = 0;
2153
2.44k
        while (target <= maximum_value) {
2154
1.22k
            ++overload_count;
2155
1.22k
            target += target_modulus;
2156
1.22k
        }
2157
1.22k
        return overload_count;
2158
1.22k
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
48
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
48
        uint512_t target = target_modulus;
2152
48
        size_t overload_count = 0;
2153
72
        while (target <= maximum_value) {
2154
24
            ++overload_count;
2155
24
            target += target_modulus;
2156
24
        }
2157
48
        return overload_count;
2158
48
    };
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Line
Count
Source
2150
22.5k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
22.5k
        uint512_t target = target_modulus;
2152
22.5k
        size_t overload_count = 0;
2153
45.1k
        while (target <= maximum_value) {
2154
22.5k
            ++overload_count;
2155
22.5k
            target += target_modulus;
2156
22.5k
        }
2157
22.5k
        return overload_count;
2158
22.5k
    };
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Line
Count
Source
2150
456
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
456
        uint512_t target = target_modulus;
2152
456
        size_t overload_count = 0;
2153
684
        while (target <= maximum_value) {
2154
228
            ++overload_count;
2155
228
            target += target_modulus;
2156
228
        }
2157
456
        return overload_count;
2158
456
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
2.57k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
2.57k
        uint512_t target = target_modulus;
2152
2.57k
        size_t overload_count = 0;
2153
5.13k
        while (target <= maximum_value) {
2154
2.56k
            ++overload_count;
2155
2.56k
            target += target_modulus;
2156
2.56k
        }
2157
2.57k
        return overload_count;
2158
2.57k
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
36
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
36
        uint512_t target = target_modulus;
2152
36
        size_t overload_count = 0;
2153
54
        while (target <= maximum_value) {
2154
18
            ++overload_count;
2155
18
            target += target_modulus;
2156
18
        }
2157
36
        return overload_count;
2158
36
    };
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Line
Count
Source
2150
2.05k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
2.05k
        uint512_t target = target_modulus;
2152
2.05k
        size_t overload_count = 0;
2153
4.10k
        while (target <= maximum_value) {
2154
2.04k
            ++overload_count;
2155
2.04k
            target += target_modulus;
2156
2.04k
        }
2157
2.05k
        return overload_count;
2158
2.05k
    };
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Line
Count
Source
2150
32
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
32
        uint512_t target = target_modulus;
2152
32
        size_t overload_count = 0;
2153
48
        while (target <= maximum_value) {
2154
16
            ++overload_count;
2155
16
            target += target_modulus;
2156
16
        }
2157
32
        return overload_count;
2158
32
    };
2159
305k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
305k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
305k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
305k
    auto diff = base_diff;
2169
305k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
305k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
614k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
309k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
309k
        prime_basis_accumulator += prime_basis;
2176
309k
    }
2177
305k
    prime_basis_accumulator = prime_basis;
2178
605k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
300k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
300k
        prime_basis_accumulator += prime_basis;
2181
300k
    }
2182
305k
    diff.assert_is_not_zero();
2183
305k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS6_
Line
Count
Source
2148
290k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
290k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
290k
        uint512_t target = target_modulus;
2152
290k
        size_t overload_count = 0;
2153
290k
        while (target <= maximum_value) {
2154
290k
            ++overload_count;
2155
290k
            target += target_modulus;
2156
290k
        }
2157
290k
        return overload_count;
2158
290k
    };
2159
290k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
290k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
290k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
290k
    auto diff = base_diff;
2169
290k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
290k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
586k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
295k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
295k
        prime_basis_accumulator += prime_basis;
2176
295k
    }
2177
290k
    prime_basis_accumulator = prime_basis;
2178
577k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
286k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
286k
        prime_basis_accumulator += prime_basis;
2181
286k
    }
2182
290k
    diff.assert_is_not_zero();
2183
290k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE19assert_is_not_equalERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E19assert_is_not_equalERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
610
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
610
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
610
        uint512_t target = target_modulus;
2152
610
        size_t overload_count = 0;
2153
610
        while (target <= maximum_value) {
2154
610
            ++overload_count;
2155
610
            target += target_modulus;
2156
610
        }
2157
610
        return overload_count;
2158
610
    };
2159
610
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
610
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
610
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
610
    auto diff = base_diff;
2169
610
    field_t<Builder> prime_basis(get_context(), modulus);
2170
610
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
1.22k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
610
        diff = diff * (base_diff - prime_basis_accumulator);
2175
610
        prime_basis_accumulator += prime_basis;
2176
610
    }
2177
610
    prime_basis_accumulator = prime_basis;
2178
1.22k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
610
        diff = diff * (base_diff + prime_basis_accumulator);
2180
610
        prime_basis_accumulator += prime_basis;
2181
610
    }
2182
610
    diff.assert_is_not_zero();
2183
610
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
24
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
24
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
24
        uint512_t target = target_modulus;
2152
24
        size_t overload_count = 0;
2153
24
        while (target <= maximum_value) {
2154
24
            ++overload_count;
2155
24
            target += target_modulus;
2156
24
        }
2157
24
        return overload_count;
2158
24
    };
2159
24
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
24
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
24
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
24
    auto diff = base_diff;
2169
24
    field_t<Builder> prime_basis(get_context(), modulus);
2170
24
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
48
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
24
        diff = diff * (base_diff - prime_basis_accumulator);
2175
24
        prime_basis_accumulator += prime_basis;
2176
24
    }
2177
24
    prime_basis_accumulator = prime_basis;
2178
24
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
24
    diff.assert_is_not_zero();
2183
24
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS9_
Line
Count
Source
2148
11.2k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
11.2k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
11.2k
        uint512_t target = target_modulus;
2152
11.2k
        size_t overload_count = 0;
2153
11.2k
        while (target <= maximum_value) {
2154
11.2k
            ++overload_count;
2155
11.2k
            target += target_modulus;
2156
11.2k
        }
2157
11.2k
        return overload_count;
2158
11.2k
    };
2159
11.2k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
11.2k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
11.2k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
11.2k
    auto diff = base_diff;
2169
11.2k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
11.2k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
22.5k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
11.2k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
11.2k
        prime_basis_accumulator += prime_basis;
2176
11.2k
    }
2177
11.2k
    prime_basis_accumulator = prime_basis;
2178
22.5k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
11.2k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
11.2k
        prime_basis_accumulator += prime_basis;
2181
11.2k
    }
2182
11.2k
    diff.assert_is_not_zero();
2183
11.2k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS9_
Line
Count
Source
2148
228
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
228
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
228
        uint512_t target = target_modulus;
2152
228
        size_t overload_count = 0;
2153
228
        while (target <= maximum_value) {
2154
228
            ++overload_count;
2155
228
            target += target_modulus;
2156
228
        }
2157
228
        return overload_count;
2158
228
    };
2159
228
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
228
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
228
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
228
    auto diff = base_diff;
2169
228
    field_t<Builder> prime_basis(get_context(), modulus);
2170
228
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
456
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
228
        diff = diff * (base_diff - prime_basis_accumulator);
2175
228
        prime_basis_accumulator += prime_basis;
2176
228
    }
2177
228
    prime_basis_accumulator = prime_basis;
2178
228
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
228
    diff.assert_is_not_zero();
2183
228
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
1.28k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
1.28k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
1.28k
        uint512_t target = target_modulus;
2152
1.28k
        size_t overload_count = 0;
2153
1.28k
        while (target <= maximum_value) {
2154
1.28k
            ++overload_count;
2155
1.28k
            target += target_modulus;
2156
1.28k
        }
2157
1.28k
        return overload_count;
2158
1.28k
    };
2159
1.28k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
1.28k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
1.28k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
1.28k
    auto diff = base_diff;
2169
1.28k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
1.28k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
2.56k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
1.27k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
1.27k
        prime_basis_accumulator += prime_basis;
2176
1.27k
    }
2177
1.28k
    prime_basis_accumulator = prime_basis;
2178
2.57k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
1.28k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
1.28k
        prime_basis_accumulator += prime_basis;
2181
1.28k
    }
2182
1.28k
    diff.assert_is_not_zero();
2183
1.28k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
18
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
18
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
18
        uint512_t target = target_modulus;
2152
18
        size_t overload_count = 0;
2153
18
        while (target <= maximum_value) {
2154
18
            ++overload_count;
2155
18
            target += target_modulus;
2156
18
        }
2157
18
        return overload_count;
2158
18
    };
2159
18
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
18
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
18
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
18
    auto diff = base_diff;
2169
18
    field_t<Builder> prime_basis(get_context(), modulus);
2170
18
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
36
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
18
        diff = diff * (base_diff - prime_basis_accumulator);
2175
18
        prime_basis_accumulator += prime_basis;
2176
18
    }
2177
18
    prime_basis_accumulator = prime_basis;
2178
18
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
18
    diff.assert_is_not_zero();
2183
18
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS9_
Line
Count
Source
2148
1.02k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
1.02k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
1.02k
        uint512_t target = target_modulus;
2152
1.02k
        size_t overload_count = 0;
2153
1.02k
        while (target <= maximum_value) {
2154
1.02k
            ++overload_count;
2155
1.02k
            target += target_modulus;
2156
1.02k
        }
2157
1.02k
        return overload_count;
2158
1.02k
    };
2159
1.02k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
1.02k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
1.02k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
1.02k
    auto diff = base_diff;
2169
1.02k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
1.02k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
2.04k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
1.02k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
1.02k
        prime_basis_accumulator += prime_basis;
2176
1.02k
    }
2177
1.02k
    prime_basis_accumulator = prime_basis;
2178
2.05k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
1.02k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
1.02k
        prime_basis_accumulator += prime_basis;
2181
1.02k
    }
2182
1.02k
    diff.assert_is_not_zero();
2183
1.02k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS9_
Line
Count
Source
2148
16
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
16
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
16
        uint512_t target = target_modulus;
2152
16
        size_t overload_count = 0;
2153
16
        while (target <= maximum_value) {
2154
16
            ++overload_count;
2155
16
            target += target_modulus;
2156
16
        }
2157
16
        return overload_count;
2158
16
    };
2159
16
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
16
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
16
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
16
    auto diff = base_diff;
2169
16
    field_t<Builder> prime_basis(get_context(), modulus);
2170
16
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
32
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
16
        diff = diff * (base_diff - prime_basis_accumulator);
2175
16
        prime_basis_accumulator += prime_basis;
2176
16
    }
2177
16
    prime_basis_accumulator = prime_basis;
2178
16
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
16
    diff.assert_is_not_zero();
2183
16
}
2184
2185
// We reduce an element's mod 2^t representation (t=4*NUM_LIMB_BITS) to size 2^s for smallest s with 2^s>p
2186
// This is much cheaper than actually reducing mod p and suffices for addition chains (where we just need not to
2187
// overflow 2^t) We also reduce any "spillage" inside the first 3 limbs, so that their range is NUM_LIMB_BITS and
2188
// not larger
2189
template <typename Builder, typename T> void bigfield<Builder, T>::self_reduce() const
2190
1.74k
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
1.74k
    if (is_constant()) {
2194
1
        return;
2195
1
    }
2196
1.74k
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
1.74k
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
1.74k
    bigfield quotient(context);
2201
2202
1.74k
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
1.74k
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
1.74k
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
1.15k
        ++maximum_quotient_bits;
2206
1.15k
    }
2207
2208
1.74k
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
0
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
0
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
1.74k
    if constexpr (HasPlookup<Builder>) {
2212
1.74k
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
1.74k
                                              static_cast<size_t>(maximum_quotient_bits));
2214
1.74k
    } else {
2215
0
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
0
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
0
                                                   "bigfield: quotient_limb too large.");
2218
0
    }
2219
2220
1.74k
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
0
           get_maximum_crt_product());
2222
0
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
0
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
0
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
0
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
0
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
0
    bigfield remainder = bigfield(
2229
0
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
0
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
0
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
0
    binary_basis_limbs[0] =
2234
0
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
0
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
0
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
0
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
0
    prime_basis_limb = remainder.prime_basis_limb;
2239
0
    set_origin_tag(new_tag);
2240
0
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE11self_reduceEv
Line
Count
Source
2190
1.03k
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
1.03k
    if (is_constant()) {
2194
1
        return;
2195
1
    }
2196
1.03k
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
1.03k
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
1.03k
    bigfield quotient(context);
2201
2202
1.03k
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
1.03k
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
1.03k
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
455
        ++maximum_quotient_bits;
2206
455
    }
2207
2208
1.03k
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
1.03k
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
1.03k
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
1.03k
    if constexpr (HasPlookup<Builder>) {
2212
1.03k
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
1.03k
                                              static_cast<size_t>(maximum_quotient_bits));
2214
1.03k
    } else {
2215
1.03k
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
1.03k
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
1.03k
                                                   "bigfield: quotient_limb too large.");
2218
1.03k
    }
2219
2220
1.03k
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
1.03k
           get_maximum_crt_product());
2222
1.03k
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
1.03k
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
1.03k
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
1.03k
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
1.03k
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
1.03k
    bigfield remainder = bigfield(
2229
1.03k
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
1.03k
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
1.03k
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
1.03k
    binary_basis_limbs[0] =
2234
1.03k
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
1.03k
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
1.03k
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
1.03k
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
1.03k
    prime_basis_limb = remainder.prime_basis_limb;
2239
1.03k
    set_origin_tag(new_tag);
2240
1.03k
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE11self_reduceEv
Line
Count
Source
2190
18
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
18
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
18
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
18
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
18
    bigfield quotient(context);
2201
2202
18
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
18
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
18
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
13
        ++maximum_quotient_bits;
2206
13
    }
2207
2208
18
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
18
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
18
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
18
    if constexpr (HasPlookup<Builder>) {
2212
18
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
18
                                              static_cast<size_t>(maximum_quotient_bits));
2214
18
    } else {
2215
18
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
18
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
18
                                                   "bigfield: quotient_limb too large.");
2218
18
    }
2219
2220
18
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
18
           get_maximum_crt_product());
2222
18
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
18
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
18
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
18
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
18
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
18
    bigfield remainder = bigfield(
2229
18
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
18
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
18
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
18
    binary_basis_limbs[0] =
2234
18
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
18
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
18
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
18
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
18
    prime_basis_limb = remainder.prime_basis_limb;
2239
18
    set_origin_tag(new_tag);
2240
18
} // namespace stdlib
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E11self_reduceEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE11self_reduceEv
Line
Count
Source
2190
22
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
22
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
22
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
22
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
22
    bigfield quotient(context);
2201
2202
22
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
22
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
22
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
19
        ++maximum_quotient_bits;
2206
19
    }
2207
2208
22
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
22
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
22
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
22
    if constexpr (HasPlookup<Builder>) {
2212
22
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
22
                                              static_cast<size_t>(maximum_quotient_bits));
2214
22
    } else {
2215
22
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
22
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
22
                                                   "bigfield: quotient_limb too large.");
2218
22
    }
2219
2220
22
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
22
           get_maximum_crt_product());
2222
22
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
22
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
22
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
22
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
22
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
22
    bigfield remainder = bigfield(
2229
22
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
22
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
22
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
22
    binary_basis_limbs[0] =
2234
22
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
22
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
22
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
22
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
22
    prime_basis_limb = remainder.prime_basis_limb;
2239
22
    set_origin_tag(new_tag);
2240
22
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE11self_reduceEv
Line
Count
Source
2190
36
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
36
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
36
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
36
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
36
    bigfield quotient(context);
2201
2202
36
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
36
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
36
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
33
        ++maximum_quotient_bits;
2206
33
    }
2207
2208
36
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
36
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
36
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
36
    if constexpr (HasPlookup<Builder>) {
2212
36
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
36
                                              static_cast<size_t>(maximum_quotient_bits));
2214
36
    } else {
2215
36
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
36
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
36
                                                   "bigfield: quotient_limb too large.");
2218
36
    }
2219
2220
36
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
36
           get_maximum_crt_product());
2222
36
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
36
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
36
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
36
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
36
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
36
    bigfield remainder = bigfield(
2229
36
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
36
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
36
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
36
    binary_basis_limbs[0] =
2234
36
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
36
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
36
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
36
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
36
    prime_basis_limb = remainder.prime_basis_limb;
2239
36
    set_origin_tag(new_tag);
2240
36
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE11self_reduceEv
Line
Count
Source
2190
114
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
114
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
114
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
114
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
114
    bigfield quotient(context);
2201
2202
114
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
114
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
114
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
114
        ++maximum_quotient_bits;
2206
114
    }
2207
2208
114
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
114
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
114
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
114
    if constexpr (HasPlookup<Builder>) {
2212
114
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
114
                                              static_cast<size_t>(maximum_quotient_bits));
2214
114
    } else {
2215
114
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
114
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
114
                                                   "bigfield: quotient_limb too large.");
2218
114
    }
2219
2220
114
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
114
           get_maximum_crt_product());
2222
114
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
114
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
114
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
114
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
114
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
114
    bigfield remainder = bigfield(
2229
114
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
114
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
114
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
114
    binary_basis_limbs[0] =
2234
114
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
114
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
114
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
114
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
114
    prime_basis_limb = remainder.prime_basis_limb;
2239
114
    set_origin_tag(new_tag);
2240
114
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE11self_reduceEv
Line
Count
Source
2190
456
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
456
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
456
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
456
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
456
    bigfield quotient(context);
2201
2202
456
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
456
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
456
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
456
        ++maximum_quotient_bits;
2206
456
    }
2207
2208
456
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
456
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
456
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
456
    if constexpr (HasPlookup<Builder>) {
2212
456
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
456
                                              static_cast<size_t>(maximum_quotient_bits));
2214
456
    } else {
2215
456
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
456
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
456
                                                   "bigfield: quotient_limb too large.");
2218
456
    }
2219
2220
456
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
456
           get_maximum_crt_product());
2222
456
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
456
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
456
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
456
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
456
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
456
    bigfield remainder = bigfield(
2229
456
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
456
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
456
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
456
    binary_basis_limbs[0] =
2234
456
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
456
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
456
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
456
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
456
    prime_basis_limb = remainder.prime_basis_limb;
2239
456
    set_origin_tag(new_tag);
2240
456
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE11self_reduceEv
Line
Count
Source
2190
13
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
13
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
13
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
13
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
13
    bigfield quotient(context);
2201
2202
13
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
13
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
13
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
13
        ++maximum_quotient_bits;
2206
13
    }
2207
2208
13
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
13
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
13
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
13
    if constexpr (HasPlookup<Builder>) {
2212
13
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
13
                                              static_cast<size_t>(maximum_quotient_bits));
2214
13
    } else {
2215
13
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
13
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
13
                                                   "bigfield: quotient_limb too large.");
2218
13
    }
2219
2220
13
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
13
           get_maximum_crt_product());
2222
13
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
13
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
13
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
13
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
13
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
13
    bigfield remainder = bigfield(
2229
13
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
13
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
13
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
13
    binary_basis_limbs[0] =
2234
13
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
13
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
13
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
13
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
13
    prime_basis_limb = remainder.prime_basis_limb;
2239
13
    set_origin_tag(new_tag);
2240
13
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE11self_reduceEv
Line
Count
Source
2190
20
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
20
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
20
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
20
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
20
    bigfield quotient(context);
2201
2202
20
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
20
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
20
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
20
        ++maximum_quotient_bits;
2206
20
    }
2207
2208
20
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
20
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
20
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
20
    if constexpr (HasPlookup<Builder>) {
2212
20
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
20
                                              static_cast<size_t>(maximum_quotient_bits));
2214
20
    } else {
2215
20
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
20
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
20
                                                   "bigfield: quotient_limb too large.");
2218
20
    }
2219
2220
20
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
20
           get_maximum_crt_product());
2222
20
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
20
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
20
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
20
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
20
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
20
    bigfield remainder = bigfield(
2229
20
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
20
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
20
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
20
    binary_basis_limbs[0] =
2234
20
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
20
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
20
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
20
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
20
    prime_basis_limb = remainder.prime_basis_limb;
2239
20
    set_origin_tag(new_tag);
2240
20
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE11self_reduceEv
Line
Count
Source
2190
12
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
12
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
12
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
12
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
12
    bigfield quotient(context);
2201
2202
12
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
12
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
12
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
12
        ++maximum_quotient_bits;
2206
12
    }
2207
2208
12
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
12
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
12
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
12
    if constexpr (HasPlookup<Builder>) {
2212
12
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
12
                                              static_cast<size_t>(maximum_quotient_bits));
2214
12
    } else {
2215
12
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
12
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
12
                                                   "bigfield: quotient_limb too large.");
2218
12
    }
2219
2220
12
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
12
           get_maximum_crt_product());
2222
12
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
12
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
12
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
12
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
12
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
12
    bigfield remainder = bigfield(
2229
12
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
12
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
12
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
12
    binary_basis_limbs[0] =
2234
12
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
12
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
12
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
12
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
12
    prime_basis_limb = remainder.prime_basis_limb;
2239
12
    set_origin_tag(new_tag);
2240
12
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE11self_reduceEv
Line
Count
Source
2190
16
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
16
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
16
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
16
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
16
    bigfield quotient(context);
2201
2202
16
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
16
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
16
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
16
        ++maximum_quotient_bits;
2206
16
    }
2207
2208
16
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
16
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
16
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
16
    if constexpr (HasPlookup<Builder>) {
2212
16
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
16
                                              static_cast<size_t>(maximum_quotient_bits));
2214
16
    } else {
2215
16
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
16
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
16
                                                   "bigfield: quotient_limb too large.");
2218
16
    }
2219
2220
16
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
16
           get_maximum_crt_product());
2222
16
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
16
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
16
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
16
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
16
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
16
    bigfield remainder = bigfield(
2229
16
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
16
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
16
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
16
    binary_basis_limbs[0] =
2234
16
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
16
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
16
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
16
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
16
    prime_basis_limb = remainder.prime_basis_limb;
2239
16
    set_origin_tag(new_tag);
2240
16
} // namespace stdlib
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E11self_reduceEv
2241
2242
/**
2243
 * Evaluate a multiply add identity with several added elements and several remainders
2244
 *
2245
 * i.e:
2246
 *
2247
 * input_left*input_to_mul + (to_add[0]..to_add[-1]) - input_quotient*modulus -
2248
 * (input_remainders[0]+..+input_remainders[-1]) = 0 (mod CRT)
2249
 *
2250
 * See detailed explanation at https://hackmd.io/LoEG5nRHQe-PvstVaD51Yw?view
2251
 *
2252
 * THIS FUNCTION IS UNSAFE TO USE IN CIRCUITS AS IT DOES NOT PROTECT AGAINST CRT OVERFLOWS.
2253
 * */
2254
template <typename Builder, typename T>
2255
void bigfield<Builder, T>::unsafe_evaluate_multiply_add(const bigfield& input_left,
2256
                                                        const bigfield& input_to_mul,
2257
                                                        const std::vector<bigfield>& to_add,
2258
                                                        const bigfield& input_quotient,
2259
                                                        const std::vector<bigfield>& input_remainders)
2260
748k
{
2261
2262
748k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
748k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
0
    input_left.sanity_check();
2266
0
    input_to_mul.sanity_check();
2267
0
    input_quotient.sanity_check();
2268
909k
    for (auto& el : to_add) {
2269
909k
        el.sanity_check();
2270
909k
    }
2271
789k
    for (auto& el : input_remainders) {
2272
789k
        el.sanity_check();
2273
789k
    }
2274
2275
0
    std::vector<bigfield> remainders(input_remainders);
2276
2277
0
    bigfield left = input_left;
2278
0
    bigfield to_mul = input_to_mul;
2279
0
    bigfield quotient = input_quotient;
2280
2281
748k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
0
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
0
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
0
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
0
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
0
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
0
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
0
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
0
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
0
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
0
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
0
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
0
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
0
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
0
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
0
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
0
    uint256_t borrow_lo_value = 0;
2308
789k
    for (const auto& remainder : input_remainders) {
2309
789k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
789k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
789k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
789k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
789k
    }
2315
0
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
0
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
0
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
0
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
0
    uint512_t max_a0(0);
2322
0
    uint512_t max_a1(0);
2323
1.65M
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
909k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
909k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
909k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
909k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
909k
    }
2329
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
0
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
0
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
748k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
186k
        ++max_lo_bits;
2337
186k
    }
2338
748k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
514k
        ++max_hi_bits;
2340
514k
    }
2341
2342
0
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
0
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
748k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
748k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
748k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
748k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
13.5k
            bigfield output(input);
2356
13.5k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
13.5k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
13.5k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
13.5k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
13.5k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
13.5k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
13.5k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
13.5k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
13.5k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
13.5k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
13.5k
            output.context = ctx;
2367
13.5k
            return output;
2368
13.5k
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ENKUlS8_E_clES8_
Line
Count
Source
2354
10.9k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
10.9k
            bigfield output(input);
2356
10.9k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
10.9k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
10.9k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
10.9k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
10.9k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
10.9k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
10.9k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
10.9k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
10.9k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
10.9k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
10.9k
            output.context = ctx;
2367
10.9k
            return output;
2368
10.9k
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ENKUlS8_E_clES8_
Line
Count
Source
2354
700
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
700
            bigfield output(input);
2356
700
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
700
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
700
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
700
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
700
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
700
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
700
            output.context = ctx;
2367
700
            return output;
2368
700
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_ENKUlSA_E_clESA_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
70
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
70
            bigfield output(input);
2356
70
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
70
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
70
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
70
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
70
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
70
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
70
            output.context = ctx;
2367
70
            return output;
2368
70
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
48
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
48
            bigfield output(input);
2356
48
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
48
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
48
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
48
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
48
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
48
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
48
            output.context = ctx;
2367
48
            return output;
2368
48
        };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Line
Count
Source
2354
1.02k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
1.02k
            bigfield output(input);
2356
1.02k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
1.02k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
1.02k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
1.02k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
1.02k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
1.02k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
1.02k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
1.02k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
1.02k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
1.02k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
1.02k
            output.context = ctx;
2367
1.02k
            return output;
2368
1.02k
        };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Line
Count
Source
2354
684
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
684
            bigfield output(input);
2356
684
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
684
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
684
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
684
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
684
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
684
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
684
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
684
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
684
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
684
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
684
            output.context = ctx;
2367
684
            return output;
2368
684
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
23
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
23
            bigfield output(input);
2356
23
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
23
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
23
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
23
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
23
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
23
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
23
            output.context = ctx;
2367
23
            return output;
2368
23
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
40
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
40
            bigfield output(input);
2356
40
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
40
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
40
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
40
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
40
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
40
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
40
            output.context = ctx;
2367
40
            return output;
2368
40
        };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Line
Count
Source
2354
20
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
20
            bigfield output(input);
2356
20
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
20
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
20
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
20
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
20
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
20
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
20
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
20
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
20
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
20
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
20
            output.context = ctx;
2367
20
            return output;
2368
20
        };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Line
Count
Source
2354
32
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
32
            bigfield output(input);
2356
32
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
32
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
32
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
32
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
32
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
32
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
32
            output.context = ctx;
2367
32
            return output;
2368
32
        };
2369
748k
        if (left.is_constant()) {
2370
5.16k
            left = convert_constant_to_fixed_witness(left);
2371
5.16k
        }
2372
748k
        if (to_mul.is_constant()) {
2373
3.88k
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
3.88k
        }
2375
748k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
748k
        if (remainders[0].is_constant()) {
2379
4.55k
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
4.55k
        }
2381
2382
748k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
748k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
748k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
789k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
41.1k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
41.1k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
41.1k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
41.1k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
41.1k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
41.1k
        }
2392
909k
        for (const auto& add : to_add) {
2393
909k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
909k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
909k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
909k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
909k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
909k
        }
2399
2400
748k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
748k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
748k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
748k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
748k
        if (needs_normalize) {
2406
37.6k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
37.6k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
37.6k
        }
2409
2410
748k
        field_t<Builder> remainder_limbs[4]{
2411
748k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
748k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
748k
                            : remainders[0].binary_basis_limbs[1].element,
2414
748k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
748k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
748k
                            : remainders[0].binary_basis_limbs[3].element,
2417
748k
        };
2418
748k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
748k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
748k
            {
2422
748k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
748k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
748k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
748k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
748k
            },
2427
748k
            {
2428
748k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
748k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
748k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
748k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
748k
            },
2433
748k
            {
2434
748k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
748k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
748k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
748k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
748k
            },
2439
748k
            {
2440
748k
                remainder_limbs[0].get_normalized_witness_index(),
2441
748k
                remainder_limbs[1].get_normalized_witness_index(),
2442
748k
                remainder_limbs[2].get_normalized_witness_index(),
2443
748k
                remainder_limbs[3].get_normalized_witness_index(),
2444
748k
            },
2445
748k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
748k
            modulus,
2447
748k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
748k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
748k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
748k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
748k
                                                       to_mul.prime_basis_limb,
2454
748k
                                                       quotient.prime_basis_limb * neg_prime,
2455
748k
                                                       -remainder_prime_limb);
2456
2457
748k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
748k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
748k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
28.1k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
28.1k
                                           lo.get_normalized_witness_index(),
2465
28.1k
                                           size_t(carry_hi_msb),
2466
28.1k
                                           size_t(carry_lo_msb));
2467
719k
        } else {
2468
719k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
719k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
719k
        }
2471
748k
    } else {
2472
0
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
0
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
0
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
0
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
0
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
0
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
0
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
0
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
0
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
0
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
0
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
0
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
0
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
0
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
0
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
0
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
0
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
0
        const field_t r2 = c0.add_two(c1, c2);
2503
0
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
0
        field_t carry_lo_0 = r0 * shift_right_2;
2506
0
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
0
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
0
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
0
        for (const auto& add_element : to_add) {
2510
0
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
0
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
0
        }
2513
0
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
0
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
0
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
0
        }
2517
0
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
0
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
0
        carry_lo += borrow_lo;
2520
0
        field_t carry_hi_0 = r2 * shift_right_2;
2521
0
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
0
        field_t carry_hi_2 = t1 * shift_right_2;
2523
0
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
0
        for (const auto& add_element : to_add) {
2526
0
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
0
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
0
        }
2529
0
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
0
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
0
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
0
        }
2533
0
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
0
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
0
        if (to_add.size() >= 2) {
2537
0
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
0
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
0
            }
2540
0
        }
2541
0
        if ((to_add.size() & 1UL) == 1UL) {
2542
0
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
0
        }
2544
0
        if (remainders.size() >= 2) {
2545
0
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
0
                linear_terms =
2547
0
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
0
            }
2549
0
        }
2550
0
        if ((remainders.size() & 1UL) == 1UL) {
2551
0
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
0
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
0
        field_t<Builder>::evaluate_polynomial_identity(
2555
0
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
0
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
0
            carry_combined = carry_combined.normalize();
2561
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
0
                carry_combined.get_normalized_witness_index(),
2563
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
0
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
0
            field_t<Builder> accumulator_midpoint =
2566
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
0
        } else {
2569
0
            carry_lo = carry_lo.normalize();
2570
0
            carry_hi = carry_hi.normalize();
2571
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
0
                                                   static_cast<size_t>(carry_lo_msb),
2573
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
0
                                                   static_cast<size_t>(carry_hi_msb),
2576
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
0
        }
2578
0
    }
2579
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Line
Count
Source
2260
691k
{
2261
2262
691k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
691k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
691k
    input_left.sanity_check();
2266
691k
    input_to_mul.sanity_check();
2267
691k
    input_quotient.sanity_check();
2268
830k
    for (auto& el : to_add) {
2269
830k
        el.sanity_check();
2270
830k
    }
2271
732k
    for (auto& el : input_remainders) {
2272
732k
        el.sanity_check();
2273
732k
    }
2274
2275
691k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
691k
    bigfield left = input_left;
2278
691k
    bigfield to_mul = input_to_mul;
2279
691k
    bigfield quotient = input_quotient;
2280
2281
691k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
691k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
691k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
691k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
691k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
691k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
691k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
691k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
691k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
691k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
691k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
691k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
691k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
691k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
691k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
691k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
691k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
691k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
691k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
691k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
691k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
691k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
691k
    uint256_t borrow_lo_value = 0;
2308
732k
    for (const auto& remainder : input_remainders) {
2309
732k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
732k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
732k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
732k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
732k
    }
2315
691k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
691k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
691k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
691k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
691k
    uint512_t max_a0(0);
2322
691k
    uint512_t max_a1(0);
2323
1.52M
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
830k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
830k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
830k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
830k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
830k
    }
2329
691k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
691k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
691k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
691k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
691k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
691k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
162k
        ++max_lo_bits;
2337
162k
    }
2338
691k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
510k
        ++max_hi_bits;
2340
510k
    }
2341
2342
691k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
691k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
691k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
691k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
691k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
691k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
691k
            bigfield output(input);
2356
691k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
691k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
691k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
691k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
691k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
691k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
691k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
691k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
691k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
691k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
691k
            output.context = ctx;
2367
691k
            return output;
2368
691k
        };
2369
691k
        if (left.is_constant()) {
2370
5.16k
            left = convert_constant_to_fixed_witness(left);
2371
5.16k
        }
2372
691k
        if (to_mul.is_constant()) {
2373
1.59k
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
1.59k
        }
2375
691k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
691k
        if (remainders[0].is_constant()) {
2379
4.19k
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
4.19k
        }
2381
2382
691k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
691k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
691k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
732k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
40.9k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
40.9k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
40.9k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
40.9k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
40.9k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
40.9k
        }
2392
830k
        for (const auto& add : to_add) {
2393
830k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
830k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
830k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
830k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
830k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
830k
        }
2399
2400
691k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
691k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
691k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
691k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
691k
        if (needs_normalize) {
2406
33.1k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
33.1k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
33.1k
        }
2409
2410
691k
        field_t<Builder> remainder_limbs[4]{
2411
691k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
691k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
691k
                            : remainders[0].binary_basis_limbs[1].element,
2414
691k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
691k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
691k
                            : remainders[0].binary_basis_limbs[3].element,
2417
691k
        };
2418
691k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
691k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
691k
            {
2422
691k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
691k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
691k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
691k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
691k
            },
2427
691k
            {
2428
691k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
691k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
691k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
691k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
691k
            },
2433
691k
            {
2434
691k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
691k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
691k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
691k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
691k
            },
2439
691k
            {
2440
691k
                remainder_limbs[0].get_normalized_witness_index(),
2441
691k
                remainder_limbs[1].get_normalized_witness_index(),
2442
691k
                remainder_limbs[2].get_normalized_witness_index(),
2443
691k
                remainder_limbs[3].get_normalized_witness_index(),
2444
691k
            },
2445
691k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
691k
            modulus,
2447
691k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
691k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
691k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
691k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
691k
                                                       to_mul.prime_basis_limb,
2454
691k
                                                       quotient.prime_basis_limb * neg_prime,
2455
691k
                                                       -remainder_prime_limb);
2456
2457
691k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
691k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
691k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
7.02k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
7.02k
                                           lo.get_normalized_witness_index(),
2465
7.02k
                                           size_t(carry_hi_msb),
2466
7.02k
                                           size_t(carry_lo_msb));
2467
684k
        } else {
2468
684k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
684k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
684k
        }
2471
691k
    } else {
2472
691k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
691k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
691k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
691k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
691k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
691k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
691k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
691k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
691k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
691k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
691k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
691k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
691k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
691k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
691k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
691k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
691k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
691k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
691k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
691k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
691k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
691k
        const field_t r2 = c0.add_two(c1, c2);
2503
691k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
691k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
691k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
691k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
691k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
691k
        for (const auto& add_element : to_add) {
2510
691k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
691k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
691k
        }
2513
691k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
691k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
691k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
691k
        }
2517
691k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
691k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
691k
        carry_lo += borrow_lo;
2520
691k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
691k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
691k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
691k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
691k
        for (const auto& add_element : to_add) {
2526
691k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
691k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
691k
        }
2529
691k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
691k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
691k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
691k
        }
2533
691k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
691k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
691k
        if (to_add.size() >= 2) {
2537
691k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
691k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
691k
            }
2540
691k
        }
2541
691k
        if ((to_add.size() & 1UL) == 1UL) {
2542
691k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
691k
        }
2544
691k
        if (remainders.size() >= 2) {
2545
691k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
691k
                linear_terms =
2547
691k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
691k
            }
2549
691k
        }
2550
691k
        if ((remainders.size() & 1UL) == 1UL) {
2551
691k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
691k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
691k
        field_t<Builder>::evaluate_polynomial_identity(
2555
691k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
691k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
691k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
691k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
691k
            carry_combined = carry_combined.normalize();
2561
691k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
691k
                carry_combined.get_normalized_witness_index(),
2563
691k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
691k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
691k
            field_t<Builder> accumulator_midpoint =
2566
691k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
691k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
691k
        } else {
2569
691k
            carry_lo = carry_lo.normalize();
2570
691k
            carry_hi = carry_hi.normalize();
2571
691k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
691k
                                                   static_cast<size_t>(carry_lo_msb),
2573
691k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
691k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
691k
                                                   static_cast<size_t>(carry_hi_msb),
2576
691k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
691k
        }
2578
691k
    }
2579
691k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Line
Count
Source
2260
378
{
2261
2262
378
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
378
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
378
    input_left.sanity_check();
2266
378
    input_to_mul.sanity_check();
2267
378
    input_quotient.sanity_check();
2268
378
    for (auto& el : to_add) {
2269
0
        el.sanity_check();
2270
0
    }
2271
378
    for (auto& el : input_remainders) {
2272
378
        el.sanity_check();
2273
378
    }
2274
2275
378
    std::vector<bigfield> remainders(input_remainders);
2276
2277
378
    bigfield left = input_left;
2278
378
    bigfield to_mul = input_to_mul;
2279
378
    bigfield quotient = input_quotient;
2280
2281
378
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
378
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
378
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
378
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
378
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
378
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
378
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
378
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
378
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
378
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
378
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
378
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
378
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
378
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
378
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
378
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
378
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
378
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
378
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
378
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
378
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
378
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
378
    uint256_t borrow_lo_value = 0;
2308
378
    for (const auto& remainder : input_remainders) {
2309
378
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
378
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
378
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
378
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
378
    }
2315
378
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
378
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
378
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
378
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
378
    uint512_t max_a0(0);
2322
378
    uint512_t max_a1(0);
2323
378
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
0
    }
2329
378
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
378
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
378
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
378
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
378
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
378
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
330
        ++max_lo_bits;
2337
330
    }
2338
378
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
8
        ++max_hi_bits;
2340
8
    }
2341
2342
378
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
378
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
378
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
378
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
378
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
378
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
378
            bigfield output(input);
2356
378
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
378
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
378
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
378
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
378
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
378
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
378
            output.context = ctx;
2367
378
            return output;
2368
378
        };
2369
378
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
378
        if (to_mul.is_constant()) {
2373
378
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
378
        }
2375
378
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
378
        if (remainders[0].is_constant()) {
2379
322
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
322
        }
2381
2382
378
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
378
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
378
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
378
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
378
        for (const auto& add : to_add) {
2393
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
0
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
0
        }
2399
2400
378
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
378
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
378
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
378
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
378
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
378
        field_t<Builder> remainder_limbs[4]{
2411
378
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
378
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
378
                            : remainders[0].binary_basis_limbs[1].element,
2414
378
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
378
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
378
                            : remainders[0].binary_basis_limbs[3].element,
2417
378
        };
2418
378
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
378
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
378
            {
2422
378
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
378
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
378
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
378
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
378
            },
2427
378
            {
2428
378
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
378
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
378
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
378
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
378
            },
2433
378
            {
2434
378
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
378
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
378
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
378
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
378
            },
2439
378
            {
2440
378
                remainder_limbs[0].get_normalized_witness_index(),
2441
378
                remainder_limbs[1].get_normalized_witness_index(),
2442
378
                remainder_limbs[2].get_normalized_witness_index(),
2443
378
                remainder_limbs[3].get_normalized_witness_index(),
2444
378
            },
2445
378
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
378
            modulus,
2447
378
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
378
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
378
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
378
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
378
                                                       to_mul.prime_basis_limb,
2454
378
                                                       quotient.prime_basis_limb * neg_prime,
2455
378
                                                       -remainder_prime_limb);
2456
2457
378
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
378
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
378
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
370
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
370
                                           lo.get_normalized_witness_index(),
2465
370
                                           size_t(carry_hi_msb),
2466
370
                                           size_t(carry_lo_msb));
2467
370
        } else {
2468
8
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
8
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
8
        }
2471
378
    } else {
2472
378
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
378
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
378
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
378
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
378
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
378
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
378
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
378
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
378
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
378
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
378
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
378
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
378
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
378
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
378
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
378
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
378
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
378
        const field_t r2 = c0.add_two(c1, c2);
2503
378
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
378
        field_t carry_lo_0 = r0 * shift_right_2;
2506
378
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
378
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
378
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
378
        for (const auto& add_element : to_add) {
2510
378
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
378
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
378
        }
2513
378
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
378
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
378
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
378
        }
2517
378
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
378
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
378
        carry_lo += borrow_lo;
2520
378
        field_t carry_hi_0 = r2 * shift_right_2;
2521
378
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
378
        field_t carry_hi_2 = t1 * shift_right_2;
2523
378
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
378
        for (const auto& add_element : to_add) {
2526
378
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
378
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
378
        }
2529
378
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
378
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
378
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
378
        }
2533
378
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
378
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
378
        if (to_add.size() >= 2) {
2537
378
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
378
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
378
            }
2540
378
        }
2541
378
        if ((to_add.size() & 1UL) == 1UL) {
2542
378
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
378
        }
2544
378
        if (remainders.size() >= 2) {
2545
378
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
378
                linear_terms =
2547
378
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
378
            }
2549
378
        }
2550
378
        if ((remainders.size() & 1UL) == 1UL) {
2551
378
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
378
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
378
        field_t<Builder>::evaluate_polynomial_identity(
2555
378
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
378
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
378
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
378
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
378
            carry_combined = carry_combined.normalize();
2561
378
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
378
                carry_combined.get_normalized_witness_index(),
2563
378
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
378
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
378
            field_t<Builder> accumulator_midpoint =
2566
378
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
378
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
378
        } else {
2569
378
            carry_lo = carry_lo.normalize();
2570
378
            carry_hi = carry_hi.normalize();
2571
378
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
378
                                                   static_cast<size_t>(carry_lo_msb),
2573
378
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
378
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
378
                                                   static_cast<size_t>(carry_hi_msb),
2576
378
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
378
        }
2578
378
    }
2579
378
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_
Line
Count
Source
2260
16
{
2261
2262
16
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
16
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
16
    input_left.sanity_check();
2266
16
    input_to_mul.sanity_check();
2267
16
    input_quotient.sanity_check();
2268
16
    for (auto& el : to_add) {
2269
0
        el.sanity_check();
2270
0
    }
2271
16
    for (auto& el : input_remainders) {
2272
16
        el.sanity_check();
2273
16
    }
2274
2275
16
    std::vector<bigfield> remainders(input_remainders);
2276
2277
16
    bigfield left = input_left;
2278
16
    bigfield to_mul = input_to_mul;
2279
16
    bigfield quotient = input_quotient;
2280
2281
16
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
16
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
16
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
16
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
16
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
16
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
16
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
16
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
16
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
16
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
16
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
16
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
16
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
16
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
16
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
16
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
16
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
16
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
16
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
16
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
16
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
16
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
16
    uint256_t borrow_lo_value = 0;
2308
16
    for (const auto& remainder : input_remainders) {
2309
16
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
16
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
16
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
16
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
16
    }
2315
16
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
16
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
16
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
16
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
16
    uint512_t max_a0(0);
2322
16
    uint512_t max_a1(0);
2323
16
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
0
    }
2329
16
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
16
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
16
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
16
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
16
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
16
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
16
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
16
        ++max_hi_bits;
2340
16
    }
2341
2342
16
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
16
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
16
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
16
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
16
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
16
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
16
            bigfield output(input);
2356
16
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
16
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
16
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
16
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
16
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
16
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
16
            output.context = ctx;
2367
16
            return output;
2368
16
        };
2369
16
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
16
        if (to_mul.is_constant()) {
2373
0
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
0
        }
2375
16
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
16
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
16
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
16
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
16
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
16
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
16
        for (const auto& add : to_add) {
2393
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
0
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
0
        }
2399
2400
16
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
16
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
16
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
16
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
16
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
16
        field_t<Builder> remainder_limbs[4]{
2411
16
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
16
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
16
                            : remainders[0].binary_basis_limbs[1].element,
2414
16
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
16
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
16
                            : remainders[0].binary_basis_limbs[3].element,
2417
16
        };
2418
16
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
16
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
16
            {
2422
16
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
16
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
16
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
16
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
16
            },
2427
16
            {
2428
16
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
16
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
16
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
16
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
16
            },
2433
16
            {
2434
16
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
16
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
16
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
16
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
16
            },
2439
16
            {
2440
16
                remainder_limbs[0].get_normalized_witness_index(),
2441
16
                remainder_limbs[1].get_normalized_witness_index(),
2442
16
                remainder_limbs[2].get_normalized_witness_index(),
2443
16
                remainder_limbs[3].get_normalized_witness_index(),
2444
16
            },
2445
16
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
16
            modulus,
2447
16
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
16
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
16
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
16
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
16
                                                       to_mul.prime_basis_limb,
2454
16
                                                       quotient.prime_basis_limb * neg_prime,
2455
16
                                                       -remainder_prime_limb);
2456
2457
16
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
16
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
16
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
0
                                           lo.get_normalized_witness_index(),
2465
0
                                           size_t(carry_hi_msb),
2466
0
                                           size_t(carry_lo_msb));
2467
16
        } else {
2468
16
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
16
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
16
        }
2471
16
    } else {
2472
16
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
16
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
16
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
16
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
16
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
16
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
16
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
16
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
16
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
16
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
16
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
16
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
16
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
16
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
16
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
16
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
16
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
16
        const field_t r2 = c0.add_two(c1, c2);
2503
16
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
16
        field_t carry_lo_0 = r0 * shift_right_2;
2506
16
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
16
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
16
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
16
        for (const auto& add_element : to_add) {
2510
16
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
16
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
16
        }
2513
16
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
16
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
16
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
16
        }
2517
16
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
16
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
16
        carry_lo += borrow_lo;
2520
16
        field_t carry_hi_0 = r2 * shift_right_2;
2521
16
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
16
        field_t carry_hi_2 = t1 * shift_right_2;
2523
16
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
16
        for (const auto& add_element : to_add) {
2526
16
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
16
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
16
        }
2529
16
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
16
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
16
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
16
        }
2533
16
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
16
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
16
        if (to_add.size() >= 2) {
2537
16
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
16
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
16
            }
2540
16
        }
2541
16
        if ((to_add.size() & 1UL) == 1UL) {
2542
16
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
16
        }
2544
16
        if (remainders.size() >= 2) {
2545
16
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
16
                linear_terms =
2547
16
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
16
            }
2549
16
        }
2550
16
        if ((remainders.size() & 1UL) == 1UL) {
2551
16
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
16
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
16
        field_t<Builder>::evaluate_polynomial_identity(
2555
16
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
16
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
16
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
16
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
16
            carry_combined = carry_combined.normalize();
2561
16
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
16
                carry_combined.get_normalized_witness_index(),
2563
16
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
16
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
16
            field_t<Builder> accumulator_midpoint =
2566
16
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
16
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
16
        } else {
2569
16
            carry_lo = carry_lo.normalize();
2570
16
            carry_hi = carry_hi.normalize();
2571
16
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
16
                                                   static_cast<size_t>(carry_lo_msb),
2573
16
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
16
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
16
                                                   static_cast<size_t>(carry_hi_msb),
2576
16
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
16
        }
2578
16
    }
2579
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
2.74k
{
2261
2262
2.74k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
2.74k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
2.74k
    input_left.sanity_check();
2266
2.74k
    input_to_mul.sanity_check();
2267
2.74k
    input_quotient.sanity_check();
2268
3.73k
    for (auto& el : to_add) {
2269
3.73k
        el.sanity_check();
2270
3.73k
    }
2271
2.74k
    for (auto& el : input_remainders) {
2272
2.74k
        el.sanity_check();
2273
2.74k
    }
2274
2275
2.74k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
2.74k
    bigfield left = input_left;
2278
2.74k
    bigfield to_mul = input_to_mul;
2279
2.74k
    bigfield quotient = input_quotient;
2280
2281
2.74k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
2.74k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
2.74k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
2.74k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
2.74k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
2.74k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
2.74k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
2.74k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
2.74k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
2.74k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
2.74k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
2.74k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
2.74k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
2.74k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
2.74k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
2.74k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
2.74k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
2.74k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
2.74k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
2.74k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
2.74k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
2.74k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
2.74k
    uint256_t borrow_lo_value = 0;
2308
2.74k
    for (const auto& remainder : input_remainders) {
2309
2.74k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
2.74k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
2.74k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
2.74k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
2.74k
    }
2315
2.74k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
2.74k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
2.74k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
2.74k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
2.74k
    uint512_t max_a0(0);
2322
2.74k
    uint512_t max_a1(0);
2323
6.47k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
3.73k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
3.73k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
3.73k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
3.73k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
3.73k
    }
2329
2.74k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
2.74k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
2.74k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
2.74k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
2.74k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
2.74k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
1.22k
        ++max_lo_bits;
2337
1.22k
    }
2338
2.74k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
40
        ++max_hi_bits;
2340
40
    }
2341
2342
2.74k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
2.74k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
2.74k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
2.74k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
2.74k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
2.74k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
2.74k
            bigfield output(input);
2356
2.74k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
2.74k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
2.74k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
2.74k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
2.74k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
2.74k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
2.74k
            output.context = ctx;
2367
2.74k
            return output;
2368
2.74k
        };
2369
2.74k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
2.74k
        if (to_mul.is_constant()) {
2373
70
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
70
        }
2375
2.74k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
2.74k
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
2.74k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
2.74k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
2.74k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
2.74k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
6
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
6
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
6
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
6
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
6
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
6
        }
2392
3.73k
        for (const auto& add : to_add) {
2393
3.73k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
3.73k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
3.73k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
3.73k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
3.73k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
3.73k
        }
2399
2400
2.74k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
2.74k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
2.74k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
2.74k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
2.74k
        if (needs_normalize) {
2406
214
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
214
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
214
        }
2409
2410
2.74k
        field_t<Builder> remainder_limbs[4]{
2411
2.74k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
2.74k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
2.74k
                            : remainders[0].binary_basis_limbs[1].element,
2414
2.74k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
2.74k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
2.74k
                            : remainders[0].binary_basis_limbs[3].element,
2417
2.74k
        };
2418
2.74k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
2.74k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
2.74k
            {
2422
2.74k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
2.74k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
2.74k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
2.74k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
2.74k
            },
2427
2.74k
            {
2428
2.74k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
2.74k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
2.74k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
2.74k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
2.74k
            },
2433
2.74k
            {
2434
2.74k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
2.74k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
2.74k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
2.74k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
2.74k
            },
2439
2.74k
            {
2440
2.74k
                remainder_limbs[0].get_normalized_witness_index(),
2441
2.74k
                remainder_limbs[1].get_normalized_witness_index(),
2442
2.74k
                remainder_limbs[2].get_normalized_witness_index(),
2443
2.74k
                remainder_limbs[3].get_normalized_witness_index(),
2444
2.74k
            },
2445
2.74k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
2.74k
            modulus,
2447
2.74k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
2.74k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
2.74k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
2.74k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
2.74k
                                                       to_mul.prime_basis_limb,
2454
2.74k
                                                       quotient.prime_basis_limb * neg_prime,
2455
2.74k
                                                       -remainder_prime_limb);
2456
2457
2.74k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
2.74k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
2.74k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
1.13k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
1.13k
                                           lo.get_normalized_witness_index(),
2465
1.13k
                                           size_t(carry_hi_msb),
2466
1.13k
                                           size_t(carry_lo_msb));
2467
1.61k
        } else {
2468
1.61k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
1.61k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
1.61k
        }
2471
2.74k
    } else {
2472
2.74k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
2.74k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
2.74k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
2.74k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
2.74k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
2.74k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
2.74k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
2.74k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
2.74k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
2.74k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
2.74k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
2.74k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
2.74k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
2.74k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
2.74k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
2.74k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
2.74k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
2.74k
        const field_t r2 = c0.add_two(c1, c2);
2503
2.74k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
2.74k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
2.74k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
2.74k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
2.74k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
2.74k
        for (const auto& add_element : to_add) {
2510
2.74k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
2.74k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
2.74k
        }
2513
2.74k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
2.74k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
2.74k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
2.74k
        }
2517
2.74k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
2.74k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
2.74k
        carry_lo += borrow_lo;
2520
2.74k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
2.74k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
2.74k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
2.74k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
2.74k
        for (const auto& add_element : to_add) {
2526
2.74k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
2.74k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
2.74k
        }
2529
2.74k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
2.74k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
2.74k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
2.74k
        }
2533
2.74k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
2.74k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
2.74k
        if (to_add.size() >= 2) {
2537
2.74k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
2.74k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
2.74k
            }
2540
2.74k
        }
2541
2.74k
        if ((to_add.size() & 1UL) == 1UL) {
2542
2.74k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
2.74k
        }
2544
2.74k
        if (remainders.size() >= 2) {
2545
2.74k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
2.74k
                linear_terms =
2547
2.74k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
2.74k
            }
2549
2.74k
        }
2550
2.74k
        if ((remainders.size() & 1UL) == 1UL) {
2551
2.74k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
2.74k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
2.74k
        field_t<Builder>::evaluate_polynomial_identity(
2555
2.74k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
2.74k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
2.74k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
2.74k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
2.74k
            carry_combined = carry_combined.normalize();
2561
2.74k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
2.74k
                carry_combined.get_normalized_witness_index(),
2563
2.74k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
2.74k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
2.74k
            field_t<Builder> accumulator_midpoint =
2566
2.74k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
2.74k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
2.74k
        } else {
2569
2.74k
            carry_lo = carry_lo.normalize();
2570
2.74k
            carry_hi = carry_hi.normalize();
2571
2.74k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
2.74k
                                                   static_cast<size_t>(carry_lo_msb),
2573
2.74k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
2.74k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
2.74k
                                                   static_cast<size_t>(carry_hi_msb),
2576
2.74k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
2.74k
        }
2578
2.74k
    }
2579
2.74k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
63
{
2261
2262
63
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
63
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
63
    input_left.sanity_check();
2266
63
    input_to_mul.sanity_check();
2267
63
    input_quotient.sanity_check();
2268
63
    for (auto& el : to_add) {
2269
26
        el.sanity_check();
2270
26
    }
2271
63
    for (auto& el : input_remainders) {
2272
63
        el.sanity_check();
2273
63
    }
2274
2275
63
    std::vector<bigfield> remainders(input_remainders);
2276
2277
63
    bigfield left = input_left;
2278
63
    bigfield to_mul = input_to_mul;
2279
63
    bigfield quotient = input_quotient;
2280
2281
63
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
63
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
63
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
63
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
63
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
63
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
63
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
63
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
63
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
63
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
63
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
63
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
63
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
63
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
63
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
63
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
63
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
63
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
63
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
63
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
63
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
63
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
63
    uint256_t borrow_lo_value = 0;
2308
63
    for (const auto& remainder : input_remainders) {
2309
63
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
63
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
63
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
63
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
63
    }
2315
63
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
63
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
63
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
63
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
63
    uint512_t max_a0(0);
2322
63
    uint512_t max_a1(0);
2323
89
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
26
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
26
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
26
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
26
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
26
    }
2329
63
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
63
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
63
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
63
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
63
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
63
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
3
        ++max_lo_bits;
2337
3
    }
2338
63
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
12
        ++max_hi_bits;
2340
12
    }
2341
2342
63
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
63
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
63
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
63
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
63
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
63
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
63
            bigfield output(input);
2356
63
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
63
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
63
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
63
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
63
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
63
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
63
            output.context = ctx;
2367
63
            return output;
2368
63
        };
2369
63
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
63
        if (to_mul.is_constant()) {
2373
48
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
48
        }
2375
63
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
63
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
63
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
63
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
63
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
63
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
63
        for (const auto& add : to_add) {
2393
26
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
26
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
26
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
26
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
26
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
26
        }
2399
2400
63
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
63
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
63
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
63
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
63
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
63
        field_t<Builder> remainder_limbs[4]{
2411
63
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
63
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
63
                            : remainders[0].binary_basis_limbs[1].element,
2414
63
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
63
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
63
                            : remainders[0].binary_basis_limbs[3].element,
2417
63
        };
2418
63
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
63
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
63
            {
2422
63
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
63
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
63
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
63
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
63
            },
2427
63
            {
2428
63
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
63
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
63
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
63
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
63
            },
2433
63
            {
2434
63
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
63
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
63
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
63
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
63
            },
2439
63
            {
2440
63
                remainder_limbs[0].get_normalized_witness_index(),
2441
63
                remainder_limbs[1].get_normalized_witness_index(),
2442
63
                remainder_limbs[2].get_normalized_witness_index(),
2443
63
                remainder_limbs[3].get_normalized_witness_index(),
2444
63
            },
2445
63
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
63
            modulus,
2447
63
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
63
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
63
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
63
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
63
                                                       to_mul.prime_basis_limb,
2454
63
                                                       quotient.prime_basis_limb * neg_prime,
2455
63
                                                       -remainder_prime_limb);
2456
2457
63
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
63
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
63
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
50
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
50
                                           lo.get_normalized_witness_index(),
2465
50
                                           size_t(carry_hi_msb),
2466
50
                                           size_t(carry_lo_msb));
2467
50
        } else {
2468
13
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
13
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
13
        }
2471
63
    } else {
2472
63
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
63
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
63
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
63
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
63
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
63
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
63
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
63
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
63
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
63
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
63
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
63
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
63
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
63
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
63
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
63
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
63
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
63
        const field_t r2 = c0.add_two(c1, c2);
2503
63
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
63
        field_t carry_lo_0 = r0 * shift_right_2;
2506
63
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
63
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
63
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
63
        for (const auto& add_element : to_add) {
2510
63
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
63
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
63
        }
2513
63
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
63
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
63
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
63
        }
2517
63
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
63
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
63
        carry_lo += borrow_lo;
2520
63
        field_t carry_hi_0 = r2 * shift_right_2;
2521
63
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
63
        field_t carry_hi_2 = t1 * shift_right_2;
2523
63
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
63
        for (const auto& add_element : to_add) {
2526
63
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
63
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
63
        }
2529
63
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
63
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
63
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
63
        }
2533
63
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
63
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
63
        if (to_add.size() >= 2) {
2537
63
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
63
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
63
            }
2540
63
        }
2541
63
        if ((to_add.size() & 1UL) == 1UL) {
2542
63
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
63
        }
2544
63
        if (remainders.size() >= 2) {
2545
63
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
63
                linear_terms =
2547
63
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
63
            }
2549
63
        }
2550
63
        if ((remainders.size() & 1UL) == 1UL) {
2551
63
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
63
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
63
        field_t<Builder>::evaluate_polynomial_identity(
2555
63
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
63
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
63
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
63
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
63
            carry_combined = carry_combined.normalize();
2561
63
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
63
                carry_combined.get_normalized_witness_index(),
2563
63
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
63
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
63
            field_t<Builder> accumulator_midpoint =
2566
63
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
63
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
63
        } else {
2569
63
            carry_lo = carry_lo.normalize();
2570
63
            carry_hi = carry_hi.normalize();
2571
63
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
63
                                                   static_cast<size_t>(carry_lo_msb),
2573
63
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
63
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
63
                                                   static_cast<size_t>(carry_hi_msb),
2576
63
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
63
        }
2578
63
    }
2579
63
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Line
Count
Source
2260
46.0k
{
2261
2262
46.0k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
46.0k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
46.0k
    input_left.sanity_check();
2266
46.0k
    input_to_mul.sanity_check();
2267
46.0k
    input_quotient.sanity_check();
2268
64.5k
    for (auto& el : to_add) {
2269
64.5k
        el.sanity_check();
2270
64.5k
    }
2271
46.1k
    for (auto& el : input_remainders) {
2272
46.1k
        el.sanity_check();
2273
46.1k
    }
2274
2275
46.0k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
46.0k
    bigfield left = input_left;
2278
46.0k
    bigfield to_mul = input_to_mul;
2279
46.0k
    bigfield quotient = input_quotient;
2280
2281
46.0k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
46.0k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
46.0k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
46.0k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
46.0k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
46.0k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
46.0k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
46.0k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
46.0k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
46.0k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
46.0k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
46.0k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
46.0k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
46.0k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
46.0k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
46.0k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
46.0k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
46.0k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
46.0k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
46.0k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
46.0k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
46.0k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
46.0k
    uint256_t borrow_lo_value = 0;
2308
46.1k
    for (const auto& remainder : input_remainders) {
2309
46.1k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
46.1k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
46.1k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
46.1k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
46.1k
    }
2315
46.0k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
46.0k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
46.0k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
46.0k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
46.0k
    uint512_t max_a0(0);
2322
46.0k
    uint512_t max_a1(0);
2323
110k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
64.5k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
64.5k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
64.5k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
64.5k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
64.5k
    }
2329
46.0k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
46.0k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
46.0k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
46.0k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
46.0k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
46.0k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
20.4k
        ++max_lo_bits;
2337
20.4k
    }
2338
46.0k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
456
        ++max_hi_bits;
2340
456
    }
2341
2342
46.0k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
46.0k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
46.0k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
46.0k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
46.0k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
46.0k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
46.0k
            bigfield output(input);
2356
46.0k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
46.0k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
46.0k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
46.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
46.0k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
46.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
46.0k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
46.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
46.0k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
46.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
46.0k
            output.context = ctx;
2367
46.0k
            return output;
2368
46.0k
        };
2369
46.0k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
46.0k
        if (to_mul.is_constant()) {
2373
1.02k
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
1.02k
        }
2375
46.0k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
46.0k
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
46.0k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
46.0k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
46.0k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
46.1k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
114
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
114
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
114
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
114
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
114
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
114
        }
2392
64.5k
        for (const auto& add : to_add) {
2393
64.5k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
64.5k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
64.5k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
64.5k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
64.5k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
64.5k
        }
2399
2400
46.0k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
46.0k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
46.0k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
46.0k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
46.0k
        if (needs_normalize) {
2406
3.76k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
3.76k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
3.76k
        }
2409
2410
46.0k
        field_t<Builder> remainder_limbs[4]{
2411
46.0k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
46.0k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
46.0k
                            : remainders[0].binary_basis_limbs[1].element,
2414
46.0k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
46.0k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
46.0k
                            : remainders[0].binary_basis_limbs[3].element,
2417
46.0k
        };
2418
46.0k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
46.0k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
46.0k
            {
2422
46.0k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
46.0k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
46.0k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
46.0k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
46.0k
            },
2427
46.0k
            {
2428
46.0k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
46.0k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
46.0k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
46.0k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
46.0k
            },
2433
46.0k
            {
2434
46.0k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
46.0k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
46.0k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
46.0k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
46.0k
            },
2439
46.0k
            {
2440
46.0k
                remainder_limbs[0].get_normalized_witness_index(),
2441
46.0k
                remainder_limbs[1].get_normalized_witness_index(),
2442
46.0k
                remainder_limbs[2].get_normalized_witness_index(),
2443
46.0k
                remainder_limbs[3].get_normalized_witness_index(),
2444
46.0k
            },
2445
46.0k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
46.0k
            modulus,
2447
46.0k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
46.0k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
46.0k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
46.0k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
46.0k
                                                       to_mul.prime_basis_limb,
2454
46.0k
                                                       quotient.prime_basis_limb * neg_prime,
2455
46.0k
                                                       -remainder_prime_limb);
2456
2457
46.0k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
46.0k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
46.0k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
18.8k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
18.8k
                                           lo.get_normalized_witness_index(),
2465
18.8k
                                           size_t(carry_hi_msb),
2466
18.8k
                                           size_t(carry_lo_msb));
2467
27.2k
        } else {
2468
27.2k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
27.2k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
27.2k
        }
2471
46.0k
    } else {
2472
46.0k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
46.0k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
46.0k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
46.0k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
46.0k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
46.0k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
46.0k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
46.0k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
46.0k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
46.0k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
46.0k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
46.0k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
46.0k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
46.0k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
46.0k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
46.0k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
46.0k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
46.0k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
46.0k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
46.0k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
46.0k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
46.0k
        const field_t r2 = c0.add_two(c1, c2);
2503
46.0k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
46.0k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
46.0k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
46.0k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
46.0k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
46.0k
        for (const auto& add_element : to_add) {
2510
46.0k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
46.0k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
46.0k
        }
2513
46.0k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
46.0k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
46.0k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
46.0k
        }
2517
46.0k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
46.0k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
46.0k
        carry_lo += borrow_lo;
2520
46.0k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
46.0k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
46.0k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
46.0k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
46.0k
        for (const auto& add_element : to_add) {
2526
46.0k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
46.0k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
46.0k
        }
2529
46.0k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
46.0k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
46.0k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
46.0k
        }
2533
46.0k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
46.0k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
46.0k
        if (to_add.size() >= 2) {
2537
46.0k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
46.0k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
46.0k
            }
2540
46.0k
        }
2541
46.0k
        if ((to_add.size() & 1UL) == 1UL) {
2542
46.0k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
46.0k
        }
2544
46.0k
        if (remainders.size() >= 2) {
2545
46.0k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
46.0k
                linear_terms =
2547
46.0k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
46.0k
            }
2549
46.0k
        }
2550
46.0k
        if ((remainders.size() & 1UL) == 1UL) {
2551
46.0k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
46.0k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
46.0k
        field_t<Builder>::evaluate_polynomial_identity(
2555
46.0k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
46.0k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
46.0k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
46.0k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
46.0k
            carry_combined = carry_combined.normalize();
2561
46.0k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
46.0k
                carry_combined.get_normalized_witness_index(),
2563
46.0k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
46.0k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
46.0k
            field_t<Builder> accumulator_midpoint =
2566
46.0k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
46.0k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
46.0k
        } else {
2569
46.0k
            carry_lo = carry_lo.normalize();
2570
46.0k
            carry_hi = carry_hi.normalize();
2571
46.0k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
46.0k
                                                   static_cast<size_t>(carry_lo_msb),
2573
46.0k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
46.0k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
46.0k
                                                   static_cast<size_t>(carry_hi_msb),
2576
46.0k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
46.0k
        }
2578
46.0k
    }
2579
46.0k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Line
Count
Source
2260
912
{
2261
2262
912
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
912
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
912
    input_left.sanity_check();
2266
912
    input_to_mul.sanity_check();
2267
912
    input_quotient.sanity_check();
2268
912
    for (auto& el : to_add) {
2269
456
        el.sanity_check();
2270
456
    }
2271
912
    for (auto& el : input_remainders) {
2272
912
        el.sanity_check();
2273
912
    }
2274
2275
912
    std::vector<bigfield> remainders(input_remainders);
2276
2277
912
    bigfield left = input_left;
2278
912
    bigfield to_mul = input_to_mul;
2279
912
    bigfield quotient = input_quotient;
2280
2281
912
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
912
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
912
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
912
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
912
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
912
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
912
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
912
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
912
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
912
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
912
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
912
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
912
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
912
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
912
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
912
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
912
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
912
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
912
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
912
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
912
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
912
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
912
    uint256_t borrow_lo_value = 0;
2308
912
    for (const auto& remainder : input_remainders) {
2309
912
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
912
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
912
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
912
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
912
    }
2315
912
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
912
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
912
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
912
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
912
    uint512_t max_a0(0);
2322
912
    uint512_t max_a1(0);
2323
1.36k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
456
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
456
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
456
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
456
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
456
    }
2329
912
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
912
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
912
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
912
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
912
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
912
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
912
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
228
        ++max_hi_bits;
2340
228
    }
2341
2342
912
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
912
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
912
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
912
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
912
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
912
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
912
            bigfield output(input);
2356
912
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
912
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
912
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
912
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
912
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
912
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
912
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
912
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
912
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
912
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
912
            output.context = ctx;
2367
912
            return output;
2368
912
        };
2369
912
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
912
        if (to_mul.is_constant()) {
2373
684
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
684
        }
2375
912
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
912
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
912
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
912
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
912
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
912
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
912
        for (const auto& add : to_add) {
2393
456
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
456
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
456
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
456
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
456
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
456
        }
2399
2400
912
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
912
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
912
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
912
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
912
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
912
        field_t<Builder> remainder_limbs[4]{
2411
912
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
912
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
912
                            : remainders[0].binary_basis_limbs[1].element,
2414
912
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
912
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
912
                            : remainders[0].binary_basis_limbs[3].element,
2417
912
        };
2418
912
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
912
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
912
            {
2422
912
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
912
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
912
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
912
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
912
            },
2427
912
            {
2428
912
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
912
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
912
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
912
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
912
            },
2433
912
            {
2434
912
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
912
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
912
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
912
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
912
            },
2439
912
            {
2440
912
                remainder_limbs[0].get_normalized_witness_index(),
2441
912
                remainder_limbs[1].get_normalized_witness_index(),
2442
912
                remainder_limbs[2].get_normalized_witness_index(),
2443
912
                remainder_limbs[3].get_normalized_witness_index(),
2444
912
            },
2445
912
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
912
            modulus,
2447
912
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
912
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
912
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
912
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
912
                                                       to_mul.prime_basis_limb,
2454
912
                                                       quotient.prime_basis_limb * neg_prime,
2455
912
                                                       -remainder_prime_limb);
2456
2457
912
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
912
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
912
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
684
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
684
                                           lo.get_normalized_witness_index(),
2465
684
                                           size_t(carry_hi_msb),
2466
684
                                           size_t(carry_lo_msb));
2467
684
        } else {
2468
228
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
228
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
228
        }
2471
912
    } else {
2472
912
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
912
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
912
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
912
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
912
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
912
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
912
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
912
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
912
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
912
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
912
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
912
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
912
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
912
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
912
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
912
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
912
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
912
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
912
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
912
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
912
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
912
        const field_t r2 = c0.add_two(c1, c2);
2503
912
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
912
        field_t carry_lo_0 = r0 * shift_right_2;
2506
912
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
912
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
912
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
912
        for (const auto& add_element : to_add) {
2510
912
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
912
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
912
        }
2513
912
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
912
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
912
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
912
        }
2517
912
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
912
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
912
        carry_lo += borrow_lo;
2520
912
        field_t carry_hi_0 = r2 * shift_right_2;
2521
912
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
912
        field_t carry_hi_2 = t1 * shift_right_2;
2523
912
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
912
        for (const auto& add_element : to_add) {
2526
912
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
912
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
912
        }
2529
912
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
912
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
912
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
912
        }
2533
912
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
912
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
912
        if (to_add.size() >= 2) {
2537
912
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
912
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
912
            }
2540
912
        }
2541
912
        if ((to_add.size() & 1UL) == 1UL) {
2542
912
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
912
        }
2544
912
        if (remainders.size() >= 2) {
2545
912
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
912
                linear_terms =
2547
912
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
912
            }
2549
912
        }
2550
912
        if ((remainders.size() & 1UL) == 1UL) {
2551
912
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
912
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
912
        field_t<Builder>::evaluate_polynomial_identity(
2555
912
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
912
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
912
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
912
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
912
            carry_combined = carry_combined.normalize();
2561
912
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
912
                carry_combined.get_normalized_witness_index(),
2563
912
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
912
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
912
            field_t<Builder> accumulator_midpoint =
2566
912
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
912
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
912
        } else {
2569
912
            carry_lo = carry_lo.normalize();
2570
912
            carry_hi = carry_hi.normalize();
2571
912
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
912
                                                   static_cast<size_t>(carry_lo_msb),
2573
912
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
912
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
912
                                                   static_cast<size_t>(carry_hi_msb),
2576
912
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
912
        }
2578
912
    }
2579
912
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
3.34k
{
2261
2262
3.34k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
3.34k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
3.34k
    input_left.sanity_check();
2266
3.34k
    input_to_mul.sanity_check();
2267
3.34k
    input_quotient.sanity_check();
2268
5.85k
    for (auto& el : to_add) {
2269
5.85k
        el.sanity_check();
2270
5.85k
    }
2271
3.35k
    for (auto& el : input_remainders) {
2272
3.35k
        el.sanity_check();
2273
3.35k
    }
2274
2275
3.34k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
3.34k
    bigfield left = input_left;
2278
3.34k
    bigfield to_mul = input_to_mul;
2279
3.34k
    bigfield quotient = input_quotient;
2280
2281
3.34k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
3.34k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
3.34k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
3.34k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
3.34k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
3.34k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
3.34k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
3.34k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
3.34k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
3.34k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
3.34k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
3.34k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
3.34k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
3.34k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
3.34k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
3.34k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
3.34k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
3.34k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
3.34k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
3.34k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
3.34k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
3.34k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
3.34k
    uint256_t borrow_lo_value = 0;
2308
3.35k
    for (const auto& remainder : input_remainders) {
2309
3.35k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
3.35k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
3.35k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
3.35k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
3.35k
    }
2315
3.34k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
3.34k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
3.34k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
3.34k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
3.34k
    uint512_t max_a0(0);
2322
3.34k
    uint512_t max_a1(0);
2323
9.19k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
5.85k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
5.85k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
5.85k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
5.85k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
5.85k
    }
2329
3.34k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
3.34k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
3.34k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
3.34k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
3.34k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
3.34k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
1.04k
        ++max_lo_bits;
2337
1.04k
    }
2338
3.34k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
1.66k
        ++max_hi_bits;
2340
1.66k
    }
2341
2342
3.34k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
3.34k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
3.34k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
3.34k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
3.34k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
3.34k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
3.34k
            bigfield output(input);
2356
3.34k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
3.34k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
3.34k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
3.34k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
3.34k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
3.34k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
3.34k
            output.context = ctx;
2367
3.34k
            return output;
2368
3.34k
        };
2369
3.34k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
3.34k
        if (to_mul.is_constant()) {
2373
13
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
13
        }
2375
3.34k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
3.34k
        if (remainders[0].is_constant()) {
2379
10
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
10
        }
2381
2382
3.34k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
3.34k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
3.34k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
3.35k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
15
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
15
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
15
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
15
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
15
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
15
        }
2392
5.85k
        for (const auto& add : to_add) {
2393
5.85k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
5.85k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
5.85k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
5.85k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
5.85k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
5.85k
        }
2399
2400
3.34k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
3.34k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
3.34k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
3.34k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
3.34k
        if (needs_normalize) {
2406
320
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
320
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
320
        }
2409
2410
3.34k
        field_t<Builder> remainder_limbs[4]{
2411
3.34k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
3.34k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
3.34k
                            : remainders[0].binary_basis_limbs[1].element,
2414
3.34k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
3.34k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
3.34k
                            : remainders[0].binary_basis_limbs[3].element,
2417
3.34k
        };
2418
3.34k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
3.34k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
3.34k
            {
2422
3.34k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
3.34k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
3.34k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
3.34k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
3.34k
            },
2427
3.34k
            {
2428
3.34k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
3.34k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
3.34k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
3.34k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
3.34k
            },
2433
3.34k
            {
2434
3.34k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
3.34k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
3.34k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
3.34k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
3.34k
            },
2439
3.34k
            {
2440
3.34k
                remainder_limbs[0].get_normalized_witness_index(),
2441
3.34k
                remainder_limbs[1].get_normalized_witness_index(),
2442
3.34k
                remainder_limbs[2].get_normalized_witness_index(),
2443
3.34k
                remainder_limbs[3].get_normalized_witness_index(),
2444
3.34k
            },
2445
3.34k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
3.34k
            modulus,
2447
3.34k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
3.34k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
3.34k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
3.34k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
3.34k
                                                       to_mul.prime_basis_limb,
2454
3.34k
                                                       quotient.prime_basis_limb * neg_prime,
2455
3.34k
                                                       -remainder_prime_limb);
2456
2457
3.34k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
3.34k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
3.34k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
13
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
13
                                           lo.get_normalized_witness_index(),
2465
13
                                           size_t(carry_hi_msb),
2466
13
                                           size_t(carry_lo_msb));
2467
3.33k
        } else {
2468
3.33k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
3.33k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
3.33k
        }
2471
3.34k
    } else {
2472
3.34k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
3.34k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
3.34k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
3.34k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
3.34k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
3.34k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
3.34k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
3.34k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
3.34k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
3.34k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
3.34k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
3.34k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
3.34k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
3.34k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
3.34k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
3.34k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
3.34k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
3.34k
        const field_t r2 = c0.add_two(c1, c2);
2503
3.34k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
3.34k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
3.34k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
3.34k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
3.34k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
3.34k
        for (const auto& add_element : to_add) {
2510
3.34k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
3.34k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
3.34k
        }
2513
3.34k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
3.34k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
3.34k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
3.34k
        }
2517
3.34k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
3.34k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
3.34k
        carry_lo += borrow_lo;
2520
3.34k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
3.34k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
3.34k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
3.34k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
3.34k
        for (const auto& add_element : to_add) {
2526
3.34k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
3.34k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
3.34k
        }
2529
3.34k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
3.34k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
3.34k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
3.34k
        }
2533
3.34k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
3.34k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
3.34k
        if (to_add.size() >= 2) {
2537
3.34k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
3.34k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
3.34k
            }
2540
3.34k
        }
2541
3.34k
        if ((to_add.size() & 1UL) == 1UL) {
2542
3.34k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
3.34k
        }
2544
3.34k
        if (remainders.size() >= 2) {
2545
3.34k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
3.34k
                linear_terms =
2547
3.34k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
3.34k
            }
2549
3.34k
        }
2550
3.34k
        if ((remainders.size() & 1UL) == 1UL) {
2551
3.34k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
3.34k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
3.34k
        field_t<Builder>::evaluate_polynomial_identity(
2555
3.34k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
3.34k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
3.34k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
3.34k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
3.34k
            carry_combined = carry_combined.normalize();
2561
3.34k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
3.34k
                carry_combined.get_normalized_witness_index(),
2563
3.34k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
3.34k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
3.34k
            field_t<Builder> accumulator_midpoint =
2566
3.34k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
3.34k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
3.34k
        } else {
2569
3.34k
            carry_lo = carry_lo.normalize();
2570
3.34k
            carry_hi = carry_hi.normalize();
2571
3.34k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
3.34k
                                                   static_cast<size_t>(carry_lo_msb),
2573
3.34k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
3.34k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
3.34k
                                                   static_cast<size_t>(carry_hi_msb),
2576
3.34k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
3.34k
        }
2578
3.34k
    }
2579
3.34k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
40
{
2261
2262
40
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
40
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
40
    input_left.sanity_check();
2266
40
    input_to_mul.sanity_check();
2267
40
    input_quotient.sanity_check();
2268
40
    for (auto& el : to_add) {
2269
10
        el.sanity_check();
2270
10
    }
2271
40
    for (auto& el : input_remainders) {
2272
40
        el.sanity_check();
2273
40
    }
2274
2275
40
    std::vector<bigfield> remainders(input_remainders);
2276
2277
40
    bigfield left = input_left;
2278
40
    bigfield to_mul = input_to_mul;
2279
40
    bigfield quotient = input_quotient;
2280
2281
40
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
40
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
40
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
40
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
40
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
40
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
40
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
40
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
40
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
40
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
40
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
40
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
40
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
40
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
40
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
40
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
40
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
40
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
40
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
40
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
40
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
40
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
40
    uint256_t borrow_lo_value = 0;
2308
40
    for (const auto& remainder : input_remainders) {
2309
40
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
40
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
40
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
40
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
40
    }
2315
40
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
40
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
40
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
40
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
40
    uint512_t max_a0(0);
2322
40
    uint512_t max_a1(0);
2323
50
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
10
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
10
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
10
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
10
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
10
    }
2329
40
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
40
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
40
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
40
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
40
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
40
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
40
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
10
        ++max_hi_bits;
2340
10
    }
2341
2342
40
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
40
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
40
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
40
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
40
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
40
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
40
            bigfield output(input);
2356
40
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
40
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
40
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
40
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
40
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
40
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
40
            output.context = ctx;
2367
40
            return output;
2368
40
        };
2369
40
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
40
        if (to_mul.is_constant()) {
2373
30
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
30
        }
2375
40
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
40
        if (remainders[0].is_constant()) {
2379
10
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
10
        }
2381
2382
40
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
40
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
40
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
40
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
40
        for (const auto& add : to_add) {
2393
10
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
10
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
10
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
10
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
10
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
10
        }
2399
2400
40
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
40
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
40
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
40
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
40
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
40
        field_t<Builder> remainder_limbs[4]{
2411
40
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
40
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
40
                            : remainders[0].binary_basis_limbs[1].element,
2414
40
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
40
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
40
                            : remainders[0].binary_basis_limbs[3].element,
2417
40
        };
2418
40
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
40
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
40
            {
2422
40
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
40
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
40
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
40
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
40
            },
2427
40
            {
2428
40
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
40
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
40
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
40
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
40
            },
2433
40
            {
2434
40
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
40
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
40
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
40
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
40
            },
2439
40
            {
2440
40
                remainder_limbs[0].get_normalized_witness_index(),
2441
40
                remainder_limbs[1].get_normalized_witness_index(),
2442
40
                remainder_limbs[2].get_normalized_witness_index(),
2443
40
                remainder_limbs[3].get_normalized_witness_index(),
2444
40
            },
2445
40
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
40
            modulus,
2447
40
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
40
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
40
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
40
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
40
                                                       to_mul.prime_basis_limb,
2454
40
                                                       quotient.prime_basis_limb * neg_prime,
2455
40
                                                       -remainder_prime_limb);
2456
2457
40
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
40
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
40
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
30
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
30
                                           lo.get_normalized_witness_index(),
2465
30
                                           size_t(carry_hi_msb),
2466
30
                                           size_t(carry_lo_msb));
2467
30
        } else {
2468
10
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
10
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
10
        }
2471
40
    } else {
2472
40
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
40
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
40
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
40
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
40
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
40
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
40
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
40
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
40
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
40
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
40
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
40
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
40
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
40
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
40
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
40
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
40
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
40
        const field_t r2 = c0.add_two(c1, c2);
2503
40
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
40
        field_t carry_lo_0 = r0 * shift_right_2;
2506
40
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
40
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
40
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
40
        for (const auto& add_element : to_add) {
2510
40
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
40
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
40
        }
2513
40
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
40
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
40
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
40
        }
2517
40
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
40
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
40
        carry_lo += borrow_lo;
2520
40
        field_t carry_hi_0 = r2 * shift_right_2;
2521
40
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
40
        field_t carry_hi_2 = t1 * shift_right_2;
2523
40
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
40
        for (const auto& add_element : to_add) {
2526
40
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
40
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
40
        }
2529
40
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
40
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
40
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
40
        }
2533
40
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
40
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
40
        if (to_add.size() >= 2) {
2537
40
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
40
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
40
            }
2540
40
        }
2541
40
        if ((to_add.size() & 1UL) == 1UL) {
2542
40
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
40
        }
2544
40
        if (remainders.size() >= 2) {
2545
40
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
40
                linear_terms =
2547
40
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
40
            }
2549
40
        }
2550
40
        if ((remainders.size() & 1UL) == 1UL) {
2551
40
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
40
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
40
        field_t<Builder>::evaluate_polynomial_identity(
2555
40
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
40
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
40
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
40
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
40
            carry_combined = carry_combined.normalize();
2561
40
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
40
                carry_combined.get_normalized_witness_index(),
2563
40
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
40
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
40
            field_t<Builder> accumulator_midpoint =
2566
40
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
40
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
40
        } else {
2569
40
            carry_lo = carry_lo.normalize();
2570
40
            carry_hi = carry_hi.normalize();
2571
40
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
40
                                                   static_cast<size_t>(carry_lo_msb),
2573
40
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
40
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
40
                                                   static_cast<size_t>(carry_hi_msb),
2576
40
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
40
        }
2578
40
    }
2579
40
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Line
Count
Source
2260
2.67k
{
2261
2262
2.67k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
2.67k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
2.67k
    input_left.sanity_check();
2266
2.67k
    input_to_mul.sanity_check();
2267
2.67k
    input_quotient.sanity_check();
2268
4.68k
    for (auto& el : to_add) {
2269
4.68k
        el.sanity_check();
2270
4.68k
    }
2271
2.68k
    for (auto& el : input_remainders) {
2272
2.68k
        el.sanity_check();
2273
2.68k
    }
2274
2275
2.67k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
2.67k
    bigfield left = input_left;
2278
2.67k
    bigfield to_mul = input_to_mul;
2279
2.67k
    bigfield quotient = input_quotient;
2280
2281
2.67k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
2.67k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
2.67k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
2.67k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
2.67k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
2.67k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
2.67k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
2.67k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
2.67k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
2.67k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
2.67k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
2.67k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
2.67k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
2.67k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
2.67k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
2.67k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
2.67k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
2.67k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
2.67k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
2.67k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
2.67k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
2.67k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
2.67k
    uint256_t borrow_lo_value = 0;
2308
2.68k
    for (const auto& remainder : input_remainders) {
2309
2.68k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
2.68k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
2.68k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
2.68k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
2.68k
    }
2315
2.67k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
2.67k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
2.67k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
2.67k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
2.67k
    uint512_t max_a0(0);
2322
2.67k
    uint512_t max_a1(0);
2323
7.35k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
4.68k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
4.68k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
4.68k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
4.68k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
4.68k
    }
2329
2.67k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
2.67k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
2.67k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
2.67k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
2.67k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
2.67k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
840
        ++max_lo_bits;
2337
840
    }
2338
2.67k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
1.33k
        ++max_hi_bits;
2340
1.33k
    }
2341
2342
2.67k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
2.67k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
2.67k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
2.67k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
2.67k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
2.67k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
2.67k
            bigfield output(input);
2356
2.67k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
2.67k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
2.67k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
2.67k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
2.67k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
2.67k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
2.67k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
2.67k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
2.67k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
2.67k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
2.67k
            output.context = ctx;
2367
2.67k
            return output;
2368
2.67k
        };
2369
2.67k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
2.67k
        if (to_mul.is_constant()) {
2373
12
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
12
        }
2375
2.67k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
2.67k
        if (remainders[0].is_constant()) {
2379
8
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
8
        }
2381
2382
2.67k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
2.67k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
2.67k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
2.68k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
12
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
12
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
12
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
12
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
12
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
12
        }
2392
4.68k
        for (const auto& add : to_add) {
2393
4.68k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
4.68k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
4.68k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
4.68k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
4.68k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
4.68k
        }
2399
2400
2.67k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
2.67k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
2.67k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
2.67k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
2.67k
        if (needs_normalize) {
2406
256
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
256
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
256
        }
2409
2410
2.67k
        field_t<Builder> remainder_limbs[4]{
2411
2.67k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
2.67k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
2.67k
                            : remainders[0].binary_basis_limbs[1].element,
2414
2.67k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
2.67k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
2.67k
                            : remainders[0].binary_basis_limbs[3].element,
2417
2.67k
        };
2418
2.67k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
2.67k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
2.67k
            {
2422
2.67k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
2.67k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
2.67k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
2.67k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
2.67k
            },
2427
2.67k
            {
2428
2.67k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
2.67k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
2.67k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
2.67k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
2.67k
            },
2433
2.67k
            {
2434
2.67k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
2.67k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
2.67k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
2.67k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
2.67k
            },
2439
2.67k
            {
2440
2.67k
                remainder_limbs[0].get_normalized_witness_index(),
2441
2.67k
                remainder_limbs[1].get_normalized_witness_index(),
2442
2.67k
                remainder_limbs[2].get_normalized_witness_index(),
2443
2.67k
                remainder_limbs[3].get_normalized_witness_index(),
2444
2.67k
            },
2445
2.67k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
2.67k
            modulus,
2447
2.67k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
2.67k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
2.67k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
2.67k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
2.67k
                                                       to_mul.prime_basis_limb,
2454
2.67k
                                                       quotient.prime_basis_limb * neg_prime,
2455
2.67k
                                                       -remainder_prime_limb);
2456
2457
2.67k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
2.67k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
2.67k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
12
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
12
                                           lo.get_normalized_witness_index(),
2465
12
                                           size_t(carry_hi_msb),
2466
12
                                           size_t(carry_lo_msb));
2467
2.66k
        } else {
2468
2.66k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
2.66k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
2.66k
        }
2471
2.67k
    } else {
2472
2.67k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
2.67k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
2.67k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
2.67k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
2.67k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
2.67k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
2.67k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
2.67k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
2.67k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
2.67k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
2.67k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
2.67k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
2.67k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
2.67k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
2.67k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
2.67k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
2.67k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
2.67k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
2.67k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
2.67k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
2.67k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
2.67k
        const field_t r2 = c0.add_two(c1, c2);
2503
2.67k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
2.67k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
2.67k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
2.67k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
2.67k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
2.67k
        for (const auto& add_element : to_add) {
2510
2.67k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
2.67k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
2.67k
        }
2513
2.67k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
2.67k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
2.67k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
2.67k
        }
2517
2.67k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
2.67k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
2.67k
        carry_lo += borrow_lo;
2520
2.67k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
2.67k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
2.67k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
2.67k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
2.67k
        for (const auto& add_element : to_add) {
2526
2.67k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
2.67k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
2.67k
        }
2529
2.67k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
2.67k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
2.67k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
2.67k
        }
2533
2.67k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
2.67k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
2.67k
        if (to_add.size() >= 2) {
2537
2.67k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
2.67k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
2.67k
            }
2540
2.67k
        }
2541
2.67k
        if ((to_add.size() & 1UL) == 1UL) {
2542
2.67k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
2.67k
        }
2544
2.67k
        if (remainders.size() >= 2) {
2545
2.67k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
2.67k
                linear_terms =
2547
2.67k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
2.67k
            }
2549
2.67k
        }
2550
2.67k
        if ((remainders.size() & 1UL) == 1UL) {
2551
2.67k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
2.67k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
2.67k
        field_t<Builder>::evaluate_polynomial_identity(
2555
2.67k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
2.67k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
2.67k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
2.67k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
2.67k
            carry_combined = carry_combined.normalize();
2561
2.67k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
2.67k
                carry_combined.get_normalized_witness_index(),
2563
2.67k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
2.67k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
2.67k
            field_t<Builder> accumulator_midpoint =
2566
2.67k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
2.67k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
2.67k
        } else {
2569
2.67k
            carry_lo = carry_lo.normalize();
2570
2.67k
            carry_hi = carry_hi.normalize();
2571
2.67k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
2.67k
                                                   static_cast<size_t>(carry_lo_msb),
2573
2.67k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
2.67k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
2.67k
                                                   static_cast<size_t>(carry_hi_msb),
2576
2.67k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
2.67k
        }
2578
2.67k
    }
2579
2.67k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Line
Count
Source
2260
32
{
2261
2262
32
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
32
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
32
    input_left.sanity_check();
2266
32
    input_to_mul.sanity_check();
2267
32
    input_quotient.sanity_check();
2268
32
    for (auto& el : to_add) {
2269
8
        el.sanity_check();
2270
8
    }
2271
32
    for (auto& el : input_remainders) {
2272
32
        el.sanity_check();
2273
32
    }
2274
2275
32
    std::vector<bigfield> remainders(input_remainders);
2276
2277
32
    bigfield left = input_left;
2278
32
    bigfield to_mul = input_to_mul;
2279
32
    bigfield quotient = input_quotient;
2280
2281
32
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
32
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
32
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
32
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
32
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
32
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
32
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
32
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
32
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
32
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
32
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
32
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
32
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
32
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
32
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
32
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
32
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
32
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
32
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
32
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
32
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
32
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
32
    uint256_t borrow_lo_value = 0;
2308
32
    for (const auto& remainder : input_remainders) {
2309
32
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
32
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
32
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
32
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
32
    }
2315
32
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
32
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
32
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
32
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
32
    uint512_t max_a0(0);
2322
32
    uint512_t max_a1(0);
2323
40
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
8
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
8
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
8
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
8
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
8
    }
2329
32
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
32
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
32
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
32
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
32
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
32
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
32
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
8
        ++max_hi_bits;
2340
8
    }
2341
2342
32
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
32
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
32
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
32
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
32
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
32
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
32
            bigfield output(input);
2356
32
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
32
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
32
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
32
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
32
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
32
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
32
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
32
            output.context = ctx;
2367
32
            return output;
2368
32
        };
2369
32
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
32
        if (to_mul.is_constant()) {
2373
24
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
24
        }
2375
32
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
32
        if (remainders[0].is_constant()) {
2379
8
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
8
        }
2381
2382
32
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
32
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
32
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
32
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
32
        for (const auto& add : to_add) {
2393
8
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
8
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
8
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
8
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
8
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
8
        }
2399
2400
32
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
32
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
32
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
32
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
32
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
32
        field_t<Builder> remainder_limbs[4]{
2411
32
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
32
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
32
                            : remainders[0].binary_basis_limbs[1].element,
2414
32
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
32
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
32
                            : remainders[0].binary_basis_limbs[3].element,
2417
32
        };
2418
32
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
32
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
32
            {
2422
32
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
32
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
32
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
32
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
32
            },
2427
32
            {
2428
32
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
32
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
32
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
32
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
32
            },
2433
32
            {
2434
32
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
32
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
32
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
32
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
32
            },
2439
32
            {
2440
32
                remainder_limbs[0].get_normalized_witness_index(),
2441
32
                remainder_limbs[1].get_normalized_witness_index(),
2442
32
                remainder_limbs[2].get_normalized_witness_index(),
2443
32
                remainder_limbs[3].get_normalized_witness_index(),
2444
32
            },
2445
32
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
32
            modulus,
2447
32
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
32
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
32
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
32
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
32
                                                       to_mul.prime_basis_limb,
2454
32
                                                       quotient.prime_basis_limb * neg_prime,
2455
32
                                                       -remainder_prime_limb);
2456
2457
32
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
32
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
32
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
24
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
24
                                           lo.get_normalized_witness_index(),
2465
24
                                           size_t(carry_hi_msb),
2466
24
                                           size_t(carry_lo_msb));
2467
24
        } else {
2468
8
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
8
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
8
        }
2471
32
    } else {
2472
32
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
32
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
32
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
32
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
32
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
32
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
32
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
32
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
32
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
32
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
32
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
32
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
32
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
32
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
32
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
32
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
32
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
32
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
32
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
32
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
32
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
32
        const field_t r2 = c0.add_two(c1, c2);
2503
32
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
32
        field_t carry_lo_0 = r0 * shift_right_2;
2506
32
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
32
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
32
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
32
        for (const auto& add_element : to_add) {
2510
32
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
32
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
32
        }
2513
32
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
32
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
32
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
32
        }
2517
32
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
32
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
32
        carry_lo += borrow_lo;
2520
32
        field_t carry_hi_0 = r2 * shift_right_2;
2521
32
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
32
        field_t carry_hi_2 = t1 * shift_right_2;
2523
32
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
32
        for (const auto& add_element : to_add) {
2526
32
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
32
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
32
        }
2529
32
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
32
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
32
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
32
        }
2533
32
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
32
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
32
        if (to_add.size() >= 2) {
2537
32
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
32
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
32
            }
2540
32
        }
2541
32
        if ((to_add.size() & 1UL) == 1UL) {
2542
32
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
32
        }
2544
32
        if (remainders.size() >= 2) {
2545
32
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
32
                linear_terms =
2547
32
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
32
            }
2549
32
        }
2550
32
        if ((remainders.size() & 1UL) == 1UL) {
2551
32
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
32
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
32
        field_t<Builder>::evaluate_polynomial_identity(
2555
32
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
32
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
32
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
32
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
32
            carry_combined = carry_combined.normalize();
2561
32
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
32
                carry_combined.get_normalized_witness_index(),
2563
32
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
32
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
32
            field_t<Builder> accumulator_midpoint =
2566
32
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
32
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
32
        } else {
2569
32
            carry_lo = carry_lo.normalize();
2570
32
            carry_hi = carry_hi.normalize();
2571
32
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
32
                                                   static_cast<size_t>(carry_lo_msb),
2573
32
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
32
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
32
                                                   static_cast<size_t>(carry_hi_msb),
2576
32
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
32
        }
2578
32
    }
2579
32
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
2580
/**
2581
 * Evaluate a quadratic relation involving multiple multiplications
2582
 *
2583
 * i.e. evalaute:
2584
 *
2585
 * (left_0 * right_0) + ... + (left_n-1 * right_n-1) + ...to_add - (input_quotient * q + ...input_remainders) = 0
2586
 *
2587
 * This method supports multiple "remainders" because, when evaluating divisions, some of these remainders are terms
2588
 * We're subtracting from our product (see msub_div for more details)
2589
 *
2590
 * The above quadratic relation can be evaluated using only a single quotient/remainder term.
2591
 *
2592
 * Params:
2593
 *
2594
 * `input_left`: left multiplication operands
2595
 * `input_right` : right multiplication operands
2596
 * `to_add` : vector of elements to add to the product
2597
 * `input_quotient` : quotient
2598
 * `input_remainders` : vector of remainders
2599
 *
2600
 * THIS METHOD IS UNSAFE TO USE IN CIRCUITS DIRECTLY AS IT LACKS OVERFLOW CHECKS.
2601
 **/
2602
template <typename Builder, typename T>
2603
void bigfield<Builder, T>::unsafe_evaluate_multiple_multiply_add(const std::vector<bigfield>& input_left,
2604
                                                                 const std::vector<bigfield>& input_right,
2605
                                                                 const std::vector<bigfield>& to_add,
2606
                                                                 const bigfield& input_quotient,
2607
                                                                 const std::vector<bigfield>& input_remainders)
2608
323k
{
2609
323k
    ASSERT(input_left.size() == input_right.size());
2610
323k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
323k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
323k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
323k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
721k
    for (auto& el : input_left) {
2617
721k
        el.sanity_check();
2618
721k
    }
2619
721k
    for (auto& el : input_right) {
2620
721k
        el.sanity_check();
2621
721k
    }
2622
569k
    for (auto& el : to_add) {
2623
569k
        el.sanity_check();
2624
569k
    }
2625
0
    input_quotient.sanity_check();
2626
323k
    for (auto& el : input_remainders) {
2627
323k
        el.sanity_check();
2628
323k
    }
2629
0
    std::vector<bigfield> remainders(input_remainders);
2630
0
    std::vector<bigfield> left(input_left);
2631
0
    std::vector<bigfield> right(input_right);
2632
0
    bigfield quotient = input_quotient;
2633
0
    const size_t num_multiplications = input_left.size();
2634
2635
323k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
721k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
721k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
721k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
721k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
721k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
721k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
721k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
721k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
721k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
721k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
721k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
721k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
721k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
721k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
721k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
721k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
721k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
721k
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_SD_E_clESD_SD_
Line
Count
Source
2637
649k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
649k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
649k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
649k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
649k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
649k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
649k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
649k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
649k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
649k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
649k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
649k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
649k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
649k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
649k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
649k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
649k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
649k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_SD_E_clESD_SD_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ENKUlSF_SF_E_clESF_SF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
Line
Count
Source
2637
3.15k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
3.15k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
3.15k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
3.15k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
3.15k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
3.15k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
3.15k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
3.15k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
3.15k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
3.15k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
3.15k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
3.15k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
3.15k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
3.15k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
3.15k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
3.15k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
3.15k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
3.15k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
Line
Count
Source
2637
55.8k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
55.8k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
55.8k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
55.8k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
55.8k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
55.8k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
55.8k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
55.8k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
55.8k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
55.8k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
55.8k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
55.8k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
55.8k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
55.8k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
55.8k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
55.8k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
55.8k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
55.8k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
Line
Count
Source
2637
7.01k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
7.01k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
7.01k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
7.01k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
7.01k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
7.01k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
7.01k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
7.01k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
7.01k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
7.01k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
7.01k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
7.01k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
7.01k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
7.01k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
7.01k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
7.01k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
7.01k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
7.01k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
Line
Count
Source
2637
5.60k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
5.60k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
5.60k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
5.60k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
5.60k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
5.60k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
5.60k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
5.60k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
5.60k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
5.60k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
5.60k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
5.60k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
5.60k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
5.60k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
5.60k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
5.60k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
5.60k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
5.60k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
0
    uint512_t max_lo = 0;
2665
0
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
0
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
0
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
0
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
0
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
0
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
0
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
0
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
0
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
0
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
0
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
0
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
0
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
0
    uint256_t borrow_lo_value(0);
2687
323k
    for (const auto& remainder : input_remainders) {
2688
323k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
323k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
323k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
323k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
323k
    }
2694
0
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
0
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
0
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
0
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
0
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
0
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
0
    uint512_t max_a0(0);
2706
0
    uint512_t max_a1(0);
2707
892k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
569k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
569k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
569k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
569k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
569k
    }
2713
0
    max_lo += max_a0;
2714
0
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
1.04M
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
721k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
721k
        max_lo += product_lo;
2720
721k
        max_hi += product_hi;
2721
721k
    }
2722
2723
0
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
0
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
0
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
323k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
71.1k
        ++max_lo_bits;
2733
71.1k
    }
2734
323k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
282k
        ++max_hi_bits;
2736
282k
    }
2737
2738
323k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
323k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
9
            bigfield output(input);
2744
9
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
9
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
9
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
9
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
9
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
9
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
9
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
9
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
9
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
9
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
9
            output.context = ctx;
2755
9
            return output;
2756
9
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_E_clESD_
Line
Count
Source
2742
1
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
1
            bigfield output(input);
2744
1
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
1
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
1
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
1
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
1
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
1
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
1
            output.context = ctx;
2755
1
            return output;
2756
1
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_E_clESD_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ENKUlSF_E_clESF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Line
Count
Source
2742
4
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
4
            bigfield output(input);
2744
4
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
4
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
4
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
4
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
4
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
4
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
4
            output.context = ctx;
2755
4
            return output;
2756
4
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
Line
Count
Source
2742
4
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
4
            bigfield output(input);
2744
4
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
4
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
4
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
4
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
4
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
4
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
4
            output.context = ctx;
2755
4
            return output;
2756
4
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
323k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
323k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
323k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
1.04M
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
721k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
721k
            if (i == 0 && right[0].is_constant()) {
2777
1
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
1
            }
2779
721k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
721k
            if (i > 0 && right[i].is_constant()) {
2783
8
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
8
            }
2785
2786
721k
            if (i > 0) {
2787
397k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
397k
                    {
2789
397k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
397k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
397k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
397k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
397k
                    },
2794
397k
                    {
2795
397k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
397k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
397k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
397k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
397k
                    },
2800
397k
                    {
2801
397k
                        ctx->zero_idx,
2802
397k
                        ctx->zero_idx,
2803
397k
                        ctx->zero_idx,
2804
397k
                        ctx->zero_idx,
2805
397k
                    },
2806
397k
                    {
2807
397k
                        ctx->zero_idx,
2808
397k
                        ctx->zero_idx,
2809
397k
                        ctx->zero_idx,
2810
397k
                        ctx->zero_idx,
2811
397k
                    },
2812
397k
                    { 0, 0, 0, 0 },
2813
397k
                    modulus,
2814
397k
                };
2815
2816
397k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
397k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
397k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
397k
                limb_0_accumulator.emplace_back(-lo_2);
2822
397k
                limb_2_accumulator.emplace_back(-hi_2);
2823
397k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
397k
            }
2825
721k
        }
2826
323k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
323k
        bool no_remainders = remainders.size() == 0;
2831
323k
        if (!no_remainders) {
2832
323k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
323k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
323k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
323k
        }
2836
323k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
569k
        for (const auto& add : to_add) {
2844
569k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
569k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
569k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
569k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
569k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
569k
        }
2850
2851
323k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
323k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
323k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
323k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
323k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
323k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
323k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
323k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
323k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
323k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
323k
        field_t<Builder> remainder_limbs[4]{
2872
323k
            accumulated_lo,
2873
323k
            remainder1,
2874
323k
            accumulated_hi,
2875
323k
            remainder3,
2876
323k
        };
2877
323k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
323k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
323k
            {
2881
323k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
323k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
323k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
323k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
323k
            },
2886
323k
            {
2887
323k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
323k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
323k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
323k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
323k
            },
2892
323k
            {
2893
323k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
323k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
323k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
323k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
323k
            },
2898
323k
            {
2899
323k
                remainder_limbs[0].get_normalized_witness_index(),
2900
323k
                remainder_limbs[1].get_normalized_witness_index(),
2901
323k
                remainder_limbs[2].get_normalized_witness_index(),
2902
323k
                remainder_limbs[3].get_normalized_witness_index(),
2903
323k
            },
2904
323k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
323k
            modulus,
2906
323k
        };
2907
2908
323k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
323k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
323k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
323k
                                                       right[0].prime_basis_limb,
2914
323k
                                                       quotient.prime_basis_limb * neg_prime,
2915
323k
                                                       -remainder_prime_limb);
2916
2917
323k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
323k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
323k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
323k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
323k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
323k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
323k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
323k
        } else {
2938
323k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
323k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
323k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
323k
    } else {
2953
0
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
0
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
0
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
0
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
0
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
0
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
0
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
0
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
0
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
0
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
0
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
0
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
0
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
0
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
0
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
0
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
0
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
0
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
0
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
0
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
0
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
0
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
0
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
0
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
0
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
0
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
0
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
0
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
0
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
0
            limb_0_accumulator.emplace_back(-lo_2);
3006
0
            limb_2_accumulator.emplace_back(-hi_2);
3007
0
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
0
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
0
        bool no_remainders = remainders.size() == 0;
3018
0
        if (!no_remainders) {
3019
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
0
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
0
        }
3023
0
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
0
        }
3030
0
        for (const auto& add : to_add) {
3031
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
0
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
0
        }
3037
3038
0
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
0
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
0
        if (accumulated_lo.is_constant()) {
3041
0
            accumulated_lo =
3042
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
0
        }
3044
0
        if (accumulated_hi.is_constant()) {
3045
0
            accumulated_hi =
3046
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
0
        }
3048
0
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
0
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
0
        if (remainder1.is_constant()) {
3051
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
0
        }
3053
0
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
0
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
0
        if (remainder3.is_constant()) {
3056
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
0
        }
3058
0
        field_t<Builder> remainder_limbs[4]{
3059
0
            accumulated_lo,
3060
0
            remainder1,
3061
0
            accumulated_hi,
3062
0
            remainder3,
3063
0
        };
3064
0
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
0
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
0
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
0
        const field_t r2 = c0.add_two(c1, c2);
3077
0
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
0
        field_t carry_lo_0 = r0 * shift_right_2;
3080
0
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
0
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
0
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
0
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
0
        carry_lo += borrow_lo;
3086
0
        field_t carry_hi_0 = r2 * shift_right_2;
3087
0
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
0
        field_t carry_hi_2 = t1 * shift_right_2;
3089
0
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
0
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
0
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
0
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
0
        field_t<Builder>::evaluate_polynomial_identity(
3099
0
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
0
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
0
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
0
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
0
        if constexpr (HasPlookup<Builder>) {
3107
0
            carry_lo = carry_lo.normalize();
3108
0
            carry_hi = carry_hi.normalize();
3109
0
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
0
                                              static_cast<size_t>(carry_lo_msb));
3111
0
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
0
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
0
        } else {
3115
0
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
0
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
0
                carry_combined = carry_combined.normalize();
3118
0
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
0
                    carry_combined.get_normalized_witness_index(),
3120
0
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
0
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
0
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
0
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
0
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
0
            } else {
3126
0
                carry_lo = carry_lo.normalize();
3127
0
                carry_hi = carry_hi.normalize();
3128
0
                ctx->decompose_into_base4_accumulators(
3129
0
                    carry_lo.get_normalized_witness_index(),
3130
0
                    static_cast<size_t>(carry_lo_msb),
3131
0
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
0
                ctx->decompose_into_base4_accumulators(
3133
0
                    carry_hi.get_normalized_witness_index(),
3134
0
                    static_cast<size_t>(carry_hi_msb),
3135
0
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
0
            }
3137
0
        }
3138
0
    }
3139
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Line
Count
Source
2608
295k
{
2609
295k
    ASSERT(input_left.size() == input_right.size());
2610
295k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
295k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
295k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
295k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
649k
    for (auto& el : input_left) {
2617
649k
        el.sanity_check();
2618
649k
    }
2619
649k
    for (auto& el : input_right) {
2620
649k
        el.sanity_check();
2621
649k
    }
2622
536k
    for (auto& el : to_add) {
2623
536k
        el.sanity_check();
2624
536k
    }
2625
295k
    input_quotient.sanity_check();
2626
295k
    for (auto& el : input_remainders) {
2627
295k
        el.sanity_check();
2628
295k
    }
2629
295k
    std::vector<bigfield> remainders(input_remainders);
2630
295k
    std::vector<bigfield> left(input_left);
2631
295k
    std::vector<bigfield> right(input_right);
2632
295k
    bigfield quotient = input_quotient;
2633
295k
    const size_t num_multiplications = input_left.size();
2634
2635
295k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
295k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
295k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
295k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
295k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
295k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
295k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
295k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
295k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
295k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
295k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
295k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
295k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
295k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
295k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
295k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
295k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
295k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
295k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
295k
    uint512_t max_lo = 0;
2665
295k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
295k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
295k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
295k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
295k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
295k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
295k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
295k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
295k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
295k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
295k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
295k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
295k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
295k
    uint256_t borrow_lo_value(0);
2687
295k
    for (const auto& remainder : input_remainders) {
2688
295k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
295k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
295k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
295k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
295k
    }
2694
295k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
295k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
295k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
295k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
295k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
295k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
295k
    uint512_t max_a0(0);
2706
295k
    uint512_t max_a1(0);
2707
831k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
536k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
536k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
536k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
536k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
536k
    }
2713
295k
    max_lo += max_a0;
2714
295k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
945k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
649k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
649k
        max_lo += product_lo;
2720
649k
        max_hi += product_hi;
2721
649k
    }
2722
2723
295k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
295k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
295k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
295k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
295k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
56.5k
        ++max_lo_bits;
2733
56.5k
    }
2734
295k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
267k
        ++max_hi_bits;
2736
267k
    }
2737
2738
295k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
295k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
295k
            bigfield output(input);
2744
295k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
295k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
295k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
295k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
295k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
295k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
295k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
295k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
295k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
295k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
295k
            output.context = ctx;
2755
295k
            return output;
2756
295k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
295k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
295k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
295k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
945k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
649k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
649k
            if (i == 0 && right[0].is_constant()) {
2777
1
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
1
            }
2779
649k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
649k
            if (i > 0 && right[i].is_constant()) {
2783
0
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
0
            }
2785
2786
649k
            if (i > 0) {
2787
354k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
354k
                    {
2789
354k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
354k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
354k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
354k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
354k
                    },
2794
354k
                    {
2795
354k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
354k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
354k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
354k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
354k
                    },
2800
354k
                    {
2801
354k
                        ctx->zero_idx,
2802
354k
                        ctx->zero_idx,
2803
354k
                        ctx->zero_idx,
2804
354k
                        ctx->zero_idx,
2805
354k
                    },
2806
354k
                    {
2807
354k
                        ctx->zero_idx,
2808
354k
                        ctx->zero_idx,
2809
354k
                        ctx->zero_idx,
2810
354k
                        ctx->zero_idx,
2811
354k
                    },
2812
354k
                    { 0, 0, 0, 0 },
2813
354k
                    modulus,
2814
354k
                };
2815
2816
354k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
354k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
354k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
354k
                limb_0_accumulator.emplace_back(-lo_2);
2822
354k
                limb_2_accumulator.emplace_back(-hi_2);
2823
354k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
354k
            }
2825
649k
        }
2826
295k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
295k
        bool no_remainders = remainders.size() == 0;
2831
295k
        if (!no_remainders) {
2832
295k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
295k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
295k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
295k
        }
2836
295k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
536k
        for (const auto& add : to_add) {
2844
536k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
536k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
536k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
536k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
536k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
536k
        }
2850
2851
295k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
295k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
295k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
295k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
295k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
295k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
295k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
295k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
295k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
295k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
295k
        field_t<Builder> remainder_limbs[4]{
2872
295k
            accumulated_lo,
2873
295k
            remainder1,
2874
295k
            accumulated_hi,
2875
295k
            remainder3,
2876
295k
        };
2877
295k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
295k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
295k
            {
2881
295k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
295k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
295k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
295k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
295k
            },
2886
295k
            {
2887
295k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
295k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
295k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
295k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
295k
            },
2892
295k
            {
2893
295k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
295k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
295k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
295k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
295k
            },
2898
295k
            {
2899
295k
                remainder_limbs[0].get_normalized_witness_index(),
2900
295k
                remainder_limbs[1].get_normalized_witness_index(),
2901
295k
                remainder_limbs[2].get_normalized_witness_index(),
2902
295k
                remainder_limbs[3].get_normalized_witness_index(),
2903
295k
            },
2904
295k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
295k
            modulus,
2906
295k
        };
2907
2908
295k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
295k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
295k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
295k
                                                       right[0].prime_basis_limb,
2914
295k
                                                       quotient.prime_basis_limb * neg_prime,
2915
295k
                                                       -remainder_prime_limb);
2916
2917
295k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
295k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
295k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
295k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
295k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
295k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
295k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
295k
        } else {
2938
295k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
295k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
295k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
295k
    } else {
2953
295k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
295k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
295k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
295k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
295k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
295k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
295k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
295k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
295k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
295k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
295k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
295k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
295k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
295k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
295k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
295k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
295k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
295k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
295k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
295k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
295k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
295k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
295k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
295k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
295k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
295k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
295k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
295k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
295k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
295k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
295k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
295k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
295k
            limb_0_accumulator.emplace_back(-lo_2);
3006
295k
            limb_2_accumulator.emplace_back(-hi_2);
3007
295k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
295k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
295k
        bool no_remainders = remainders.size() == 0;
3018
295k
        if (!no_remainders) {
3019
295k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
295k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
295k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
295k
        }
3023
295k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
295k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
295k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
295k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
295k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
295k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
295k
        }
3030
295k
        for (const auto& add : to_add) {
3031
295k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
295k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
295k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
295k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
295k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
295k
        }
3037
3038
295k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
295k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
295k
        if (accumulated_lo.is_constant()) {
3041
295k
            accumulated_lo =
3042
295k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
295k
        }
3044
295k
        if (accumulated_hi.is_constant()) {
3045
295k
            accumulated_hi =
3046
295k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
295k
        }
3048
295k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
295k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
295k
        if (remainder1.is_constant()) {
3051
295k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
295k
        }
3053
295k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
295k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
295k
        if (remainder3.is_constant()) {
3056
295k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
295k
        }
3058
295k
        field_t<Builder> remainder_limbs[4]{
3059
295k
            accumulated_lo,
3060
295k
            remainder1,
3061
295k
            accumulated_hi,
3062
295k
            remainder3,
3063
295k
        };
3064
295k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
295k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
295k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
295k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
295k
        const field_t r2 = c0.add_two(c1, c2);
3077
295k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
295k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
295k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
295k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
295k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
295k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
295k
        carry_lo += borrow_lo;
3086
295k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
295k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
295k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
295k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
295k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
295k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
295k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
295k
        field_t<Builder>::evaluate_polynomial_identity(
3099
295k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
295k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
295k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
295k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
295k
        if constexpr (HasPlookup<Builder>) {
3107
295k
            carry_lo = carry_lo.normalize();
3108
295k
            carry_hi = carry_hi.normalize();
3109
295k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
295k
                                              static_cast<size_t>(carry_lo_msb));
3111
295k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
295k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
295k
        } else {
3115
295k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
295k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
295k
                carry_combined = carry_combined.normalize();
3118
295k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
295k
                    carry_combined.get_normalized_witness_index(),
3120
295k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
295k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
295k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
295k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
295k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
295k
            } else {
3126
295k
                carry_lo = carry_lo.normalize();
3127
295k
                carry_hi = carry_hi.normalize();
3128
295k
                ctx->decompose_into_base4_accumulators(
3129
295k
                    carry_lo.get_normalized_witness_index(),
3130
295k
                    static_cast<size_t>(carry_lo_msb),
3131
295k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
295k
                ctx->decompose_into_base4_accumulators(
3133
295k
                    carry_hi.get_normalized_witness_index(),
3134
295k
                    static_cast<size_t>(carry_hi_msb),
3135
295k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
295k
            }
3137
295k
        }
3138
295k
    }
3139
295k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
Line
Count
Source
2608
1.29k
{
2609
1.29k
    ASSERT(input_left.size() == input_right.size());
2610
1.29k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
1.29k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
1.29k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
1.29k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
3.15k
    for (auto& el : input_left) {
2617
3.15k
        el.sanity_check();
2618
3.15k
    }
2619
3.15k
    for (auto& el : input_right) {
2620
3.15k
        el.sanity_check();
2621
3.15k
    }
2622
1.37k
    for (auto& el : to_add) {
2623
1.37k
        el.sanity_check();
2624
1.37k
    }
2625
1.29k
    input_quotient.sanity_check();
2626
1.29k
    for (auto& el : input_remainders) {
2627
1.29k
        el.sanity_check();
2628
1.29k
    }
2629
1.29k
    std::vector<bigfield> remainders(input_remainders);
2630
1.29k
    std::vector<bigfield> left(input_left);
2631
1.29k
    std::vector<bigfield> right(input_right);
2632
1.29k
    bigfield quotient = input_quotient;
2633
1.29k
    const size_t num_multiplications = input_left.size();
2634
2635
1.29k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
1.29k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
1.29k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
1.29k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
1.29k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
1.29k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
1.29k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
1.29k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
1.29k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
1.29k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
1.29k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
1.29k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
1.29k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
1.29k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
1.29k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
1.29k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
1.29k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
1.29k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
1.29k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
1.29k
    uint512_t max_lo = 0;
2665
1.29k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
1.29k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
1.29k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
1.29k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
1.29k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
1.29k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
1.29k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
1.29k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
1.29k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
1.29k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
1.29k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
1.29k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
1.29k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
1.29k
    uint256_t borrow_lo_value(0);
2687
1.29k
    for (const auto& remainder : input_remainders) {
2688
1.29k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
1.29k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
1.29k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
1.29k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
1.29k
    }
2694
1.29k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
1.29k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
1.29k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
1.29k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
1.29k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
1.29k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
1.29k
    uint512_t max_a0(0);
2706
1.29k
    uint512_t max_a1(0);
2707
2.66k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
1.37k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
1.37k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
1.37k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
1.37k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
1.37k
    }
2713
1.29k
    max_lo += max_a0;
2714
1.29k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
4.44k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
3.15k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
3.15k
        max_lo += product_lo;
2720
3.15k
        max_hi += product_hi;
2721
3.15k
    }
2722
2723
1.29k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
1.29k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
1.29k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
1.29k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
1.29k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
585
        ++max_lo_bits;
2733
585
    }
2734
1.29k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
594
        ++max_hi_bits;
2736
594
    }
2737
2738
1.29k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
1.29k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
1.29k
            bigfield output(input);
2744
1.29k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
1.29k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
1.29k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
1.29k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
1.29k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
1.29k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
1.29k
            output.context = ctx;
2755
1.29k
            return output;
2756
1.29k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
1.29k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
1.29k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
1.29k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
4.44k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
3.15k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
3.15k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
3.15k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
3.15k
            if (i > 0 && right[i].is_constant()) {
2783
0
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
0
            }
2785
2786
3.15k
            if (i > 0) {
2787
1.86k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
1.86k
                    {
2789
1.86k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
1.86k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
1.86k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
1.86k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
1.86k
                    },
2794
1.86k
                    {
2795
1.86k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
1.86k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
1.86k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
1.86k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
1.86k
                    },
2800
1.86k
                    {
2801
1.86k
                        ctx->zero_idx,
2802
1.86k
                        ctx->zero_idx,
2803
1.86k
                        ctx->zero_idx,
2804
1.86k
                        ctx->zero_idx,
2805
1.86k
                    },
2806
1.86k
                    {
2807
1.86k
                        ctx->zero_idx,
2808
1.86k
                        ctx->zero_idx,
2809
1.86k
                        ctx->zero_idx,
2810
1.86k
                        ctx->zero_idx,
2811
1.86k
                    },
2812
1.86k
                    { 0, 0, 0, 0 },
2813
1.86k
                    modulus,
2814
1.86k
                };
2815
2816
1.86k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
1.86k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
1.86k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
1.86k
                limb_0_accumulator.emplace_back(-lo_2);
2822
1.86k
                limb_2_accumulator.emplace_back(-hi_2);
2823
1.86k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
1.86k
            }
2825
3.15k
        }
2826
1.29k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
1.29k
        bool no_remainders = remainders.size() == 0;
2831
1.29k
        if (!no_remainders) {
2832
1.29k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
1.29k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
1.29k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
1.29k
        }
2836
1.29k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
1.37k
        for (const auto& add : to_add) {
2844
1.37k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
1.37k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
1.37k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
1.37k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
1.37k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
1.37k
        }
2850
2851
1.29k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
1.29k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
1.29k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
1.29k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
1.29k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
1.29k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
1.29k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
1.29k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
1.29k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
1.29k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
1.29k
        field_t<Builder> remainder_limbs[4]{
2872
1.29k
            accumulated_lo,
2873
1.29k
            remainder1,
2874
1.29k
            accumulated_hi,
2875
1.29k
            remainder3,
2876
1.29k
        };
2877
1.29k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
1.29k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
1.29k
            {
2881
1.29k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
1.29k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
1.29k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
1.29k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
1.29k
            },
2886
1.29k
            {
2887
1.29k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
1.29k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
1.29k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
1.29k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
1.29k
            },
2892
1.29k
            {
2893
1.29k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
1.29k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
1.29k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
1.29k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
1.29k
            },
2898
1.29k
            {
2899
1.29k
                remainder_limbs[0].get_normalized_witness_index(),
2900
1.29k
                remainder_limbs[1].get_normalized_witness_index(),
2901
1.29k
                remainder_limbs[2].get_normalized_witness_index(),
2902
1.29k
                remainder_limbs[3].get_normalized_witness_index(),
2903
1.29k
            },
2904
1.29k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
1.29k
            modulus,
2906
1.29k
        };
2907
2908
1.29k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
1.29k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
1.29k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
1.29k
                                                       right[0].prime_basis_limb,
2914
1.29k
                                                       quotient.prime_basis_limb * neg_prime,
2915
1.29k
                                                       -remainder_prime_limb);
2916
2917
1.29k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
1.29k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
1.29k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
1.29k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
1.29k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
1.29k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
1.29k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
1.29k
        } else {
2938
1.29k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
1.29k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
1.29k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
1.29k
    } else {
2953
1.29k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
1.29k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
1.29k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
1.29k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
1.29k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
1.29k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
1.29k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
1.29k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
1.29k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
1.29k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
1.29k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
1.29k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
1.29k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
1.29k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
1.29k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
1.29k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
1.29k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
1.29k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
1.29k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
1.29k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
1.29k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
1.29k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
1.29k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
1.29k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
1.29k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
1.29k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
1.29k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
1.29k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
1.29k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
1.29k
            limb_0_accumulator.emplace_back(-lo_2);
3006
1.29k
            limb_2_accumulator.emplace_back(-hi_2);
3007
1.29k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
1.29k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
1.29k
        bool no_remainders = remainders.size() == 0;
3018
1.29k
        if (!no_remainders) {
3019
1.29k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
1.29k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
1.29k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
1.29k
        }
3023
1.29k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
1.29k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
1.29k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
1.29k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
1.29k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
1.29k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
1.29k
        }
3030
1.29k
        for (const auto& add : to_add) {
3031
1.29k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
1.29k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
1.29k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
1.29k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
1.29k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
1.29k
        }
3037
3038
1.29k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
1.29k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
1.29k
        if (accumulated_lo.is_constant()) {
3041
1.29k
            accumulated_lo =
3042
1.29k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
1.29k
        }
3044
1.29k
        if (accumulated_hi.is_constant()) {
3045
1.29k
            accumulated_hi =
3046
1.29k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
1.29k
        }
3048
1.29k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
1.29k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
1.29k
        if (remainder1.is_constant()) {
3051
1.29k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
1.29k
        }
3053
1.29k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
1.29k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
1.29k
        if (remainder3.is_constant()) {
3056
1.29k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
1.29k
        }
3058
1.29k
        field_t<Builder> remainder_limbs[4]{
3059
1.29k
            accumulated_lo,
3060
1.29k
            remainder1,
3061
1.29k
            accumulated_hi,
3062
1.29k
            remainder3,
3063
1.29k
        };
3064
1.29k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
1.29k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
1.29k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
1.29k
        const field_t r2 = c0.add_two(c1, c2);
3077
1.29k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
1.29k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
1.29k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
1.29k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
1.29k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
1.29k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
1.29k
        carry_lo += borrow_lo;
3086
1.29k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
1.29k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
1.29k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
1.29k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
1.29k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
1.29k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
1.29k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
1.29k
        field_t<Builder>::evaluate_polynomial_identity(
3099
1.29k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
1.29k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
1.29k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
1.29k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
1.29k
        if constexpr (HasPlookup<Builder>) {
3107
1.29k
            carry_lo = carry_lo.normalize();
3108
1.29k
            carry_hi = carry_hi.normalize();
3109
1.29k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
1.29k
                                              static_cast<size_t>(carry_lo_msb));
3111
1.29k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
1.29k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
1.29k
        } else {
3115
1.29k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
1.29k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
1.29k
                carry_combined = carry_combined.normalize();
3118
1.29k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
1.29k
                    carry_combined.get_normalized_witness_index(),
3120
1.29k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
1.29k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
1.29k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
1.29k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
1.29k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
1.29k
            } else {
3126
1.29k
                carry_lo = carry_lo.normalize();
3127
1.29k
                carry_hi = carry_hi.normalize();
3128
1.29k
                ctx->decompose_into_base4_accumulators(
3129
1.29k
                    carry_lo.get_normalized_witness_index(),
3130
1.29k
                    static_cast<size_t>(carry_lo_msb),
3131
1.29k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
1.29k
                ctx->decompose_into_base4_accumulators(
3133
1.29k
                    carry_hi.get_normalized_witness_index(),
3134
1.29k
                    static_cast<size_t>(carry_hi_msb),
3135
1.29k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
1.29k
            }
3137
1.29k
        }
3138
1.29k
    }
3139
1.29k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
Line
Count
Source
2608
22.4k
{
2609
22.4k
    ASSERT(input_left.size() == input_right.size());
2610
22.4k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
22.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
22.4k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
22.4k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
55.8k
    for (auto& el : input_left) {
2617
55.8k
        el.sanity_check();
2618
55.8k
    }
2619
55.8k
    for (auto& el : input_right) {
2620
55.8k
        el.sanity_check();
2621
55.8k
    }
2622
26.2k
    for (auto& el : to_add) {
2623
26.2k
        el.sanity_check();
2624
26.2k
    }
2625
22.4k
    input_quotient.sanity_check();
2626
22.4k
    for (auto& el : input_remainders) {
2627
22.4k
        el.sanity_check();
2628
22.4k
    }
2629
22.4k
    std::vector<bigfield> remainders(input_remainders);
2630
22.4k
    std::vector<bigfield> left(input_left);
2631
22.4k
    std::vector<bigfield> right(input_right);
2632
22.4k
    bigfield quotient = input_quotient;
2633
22.4k
    const size_t num_multiplications = input_left.size();
2634
2635
22.4k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
22.4k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
22.4k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
22.4k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
22.4k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
22.4k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
22.4k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
22.4k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
22.4k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
22.4k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
22.4k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
22.4k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
22.4k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
22.4k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
22.4k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
22.4k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
22.4k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
22.4k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
22.4k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
22.4k
    uint512_t max_lo = 0;
2665
22.4k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
22.4k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
22.4k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
22.4k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
22.4k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
22.4k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
22.4k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
22.4k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
22.4k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
22.4k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
22.4k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
22.4k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
22.4k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
22.4k
    uint256_t borrow_lo_value(0);
2687
22.4k
    for (const auto& remainder : input_remainders) {
2688
22.4k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
22.4k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
22.4k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
22.4k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
22.4k
    }
2694
22.4k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
22.4k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
22.4k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
22.4k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
22.4k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
22.4k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
22.4k
    uint512_t max_a0(0);
2706
22.4k
    uint512_t max_a1(0);
2707
48.6k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
26.2k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
26.2k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
26.2k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
26.2k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
26.2k
    }
2713
22.4k
    max_lo += max_a0;
2714
22.4k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
78.3k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
55.8k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
55.8k
        max_lo += product_lo;
2720
55.8k
        max_hi += product_hi;
2721
55.8k
    }
2722
2723
22.4k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
22.4k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
22.4k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
22.4k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
22.4k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
11.1k
        ++max_lo_bits;
2733
11.1k
    }
2734
22.4k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
11.2k
        ++max_hi_bits;
2736
11.2k
    }
2737
2738
22.4k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
22.4k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
22.4k
            bigfield output(input);
2744
22.4k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
22.4k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
22.4k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
22.4k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
22.4k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
22.4k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
22.4k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
22.4k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
22.4k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
22.4k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
22.4k
            output.context = ctx;
2755
22.4k
            return output;
2756
22.4k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
22.4k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
22.4k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
22.4k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
78.3k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
55.8k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
55.8k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
55.8k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
55.8k
            if (i > 0 && right[i].is_constant()) {
2783
0
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
0
            }
2785
2786
55.8k
            if (i > 0) {
2787
33.4k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
33.4k
                    {
2789
33.4k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
33.4k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
33.4k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
33.4k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
33.4k
                    },
2794
33.4k
                    {
2795
33.4k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
33.4k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
33.4k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
33.4k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
33.4k
                    },
2800
33.4k
                    {
2801
33.4k
                        ctx->zero_idx,
2802
33.4k
                        ctx->zero_idx,
2803
33.4k
                        ctx->zero_idx,
2804
33.4k
                        ctx->zero_idx,
2805
33.4k
                    },
2806
33.4k
                    {
2807
33.4k
                        ctx->zero_idx,
2808
33.4k
                        ctx->zero_idx,
2809
33.4k
                        ctx->zero_idx,
2810
33.4k
                        ctx->zero_idx,
2811
33.4k
                    },
2812
33.4k
                    { 0, 0, 0, 0 },
2813
33.4k
                    modulus,
2814
33.4k
                };
2815
2816
33.4k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
33.4k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
33.4k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
33.4k
                limb_0_accumulator.emplace_back(-lo_2);
2822
33.4k
                limb_2_accumulator.emplace_back(-hi_2);
2823
33.4k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
33.4k
            }
2825
55.8k
        }
2826
22.4k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
22.4k
        bool no_remainders = remainders.size() == 0;
2831
22.4k
        if (!no_remainders) {
2832
22.4k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
22.4k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
22.4k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
22.4k
        }
2836
22.4k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
26.2k
        for (const auto& add : to_add) {
2844
26.2k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
26.2k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
26.2k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
26.2k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
26.2k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
26.2k
        }
2850
2851
22.4k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
22.4k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
22.4k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
22.4k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
22.4k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
22.4k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
22.4k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
22.4k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
22.4k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
22.4k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
22.4k
        field_t<Builder> remainder_limbs[4]{
2872
22.4k
            accumulated_lo,
2873
22.4k
            remainder1,
2874
22.4k
            accumulated_hi,
2875
22.4k
            remainder3,
2876
22.4k
        };
2877
22.4k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
22.4k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
22.4k
            {
2881
22.4k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
22.4k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
22.4k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
22.4k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
22.4k
            },
2886
22.4k
            {
2887
22.4k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
22.4k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
22.4k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
22.4k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
22.4k
            },
2892
22.4k
            {
2893
22.4k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
22.4k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
22.4k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
22.4k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
22.4k
            },
2898
22.4k
            {
2899
22.4k
                remainder_limbs[0].get_normalized_witness_index(),
2900
22.4k
                remainder_limbs[1].get_normalized_witness_index(),
2901
22.4k
                remainder_limbs[2].get_normalized_witness_index(),
2902
22.4k
                remainder_limbs[3].get_normalized_witness_index(),
2903
22.4k
            },
2904
22.4k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
22.4k
            modulus,
2906
22.4k
        };
2907
2908
22.4k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
22.4k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
22.4k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
22.4k
                                                       right[0].prime_basis_limb,
2914
22.4k
                                                       quotient.prime_basis_limb * neg_prime,
2915
22.4k
                                                       -remainder_prime_limb);
2916
2917
22.4k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
22.4k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
22.4k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
22.4k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
22.4k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
22.4k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
22.4k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
22.4k
        } else {
2938
22.4k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
22.4k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
22.4k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
22.4k
    } else {
2953
22.4k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
22.4k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
22.4k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
22.4k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
22.4k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
22.4k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
22.4k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
22.4k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
22.4k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
22.4k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
22.4k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
22.4k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
22.4k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
22.4k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
22.4k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
22.4k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
22.4k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
22.4k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
22.4k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
22.4k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
22.4k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
22.4k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
22.4k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
22.4k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
22.4k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
22.4k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
22.4k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
22.4k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
22.4k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
22.4k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
22.4k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
22.4k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
22.4k
            limb_0_accumulator.emplace_back(-lo_2);
3006
22.4k
            limb_2_accumulator.emplace_back(-hi_2);
3007
22.4k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
22.4k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
22.4k
        bool no_remainders = remainders.size() == 0;
3018
22.4k
        if (!no_remainders) {
3019
22.4k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
22.4k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
22.4k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
22.4k
        }
3023
22.4k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
22.4k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
22.4k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
22.4k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
22.4k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
22.4k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
22.4k
        }
3030
22.4k
        for (const auto& add : to_add) {
3031
22.4k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
22.4k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
22.4k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
22.4k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
22.4k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
22.4k
        }
3037
3038
22.4k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
22.4k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
22.4k
        if (accumulated_lo.is_constant()) {
3041
22.4k
            accumulated_lo =
3042
22.4k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
22.4k
        }
3044
22.4k
        if (accumulated_hi.is_constant()) {
3045
22.4k
            accumulated_hi =
3046
22.4k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
22.4k
        }
3048
22.4k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
22.4k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
22.4k
        if (remainder1.is_constant()) {
3051
22.4k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
22.4k
        }
3053
22.4k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
22.4k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
22.4k
        if (remainder3.is_constant()) {
3056
22.4k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
22.4k
        }
3058
22.4k
        field_t<Builder> remainder_limbs[4]{
3059
22.4k
            accumulated_lo,
3060
22.4k
            remainder1,
3061
22.4k
            accumulated_hi,
3062
22.4k
            remainder3,
3063
22.4k
        };
3064
22.4k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
22.4k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
22.4k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
22.4k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
22.4k
        const field_t r2 = c0.add_two(c1, c2);
3077
22.4k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
22.4k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
22.4k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
22.4k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
22.4k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
22.4k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
22.4k
        carry_lo += borrow_lo;
3086
22.4k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
22.4k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
22.4k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
22.4k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
22.4k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
22.4k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
22.4k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
22.4k
        field_t<Builder>::evaluate_polynomial_identity(
3099
22.4k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
22.4k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
22.4k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
22.4k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
22.4k
        if constexpr (HasPlookup<Builder>) {
3107
22.4k
            carry_lo = carry_lo.normalize();
3108
22.4k
            carry_hi = carry_hi.normalize();
3109
22.4k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
22.4k
                                              static_cast<size_t>(carry_lo_msb));
3111
22.4k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
22.4k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
22.4k
        } else {
3115
22.4k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
22.4k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
22.4k
                carry_combined = carry_combined.normalize();
3118
22.4k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
22.4k
                    carry_combined.get_normalized_witness_index(),
3120
22.4k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
22.4k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
22.4k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
22.4k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
22.4k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
22.4k
            } else {
3126
22.4k
                carry_lo = carry_lo.normalize();
3127
22.4k
                carry_hi = carry_hi.normalize();
3128
22.4k
                ctx->decompose_into_base4_accumulators(
3129
22.4k
                    carry_lo.get_normalized_witness_index(),
3130
22.4k
                    static_cast<size_t>(carry_lo_msb),
3131
22.4k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
22.4k
                ctx->decompose_into_base4_accumulators(
3133
22.4k
                    carry_hi.get_normalized_witness_index(),
3134
22.4k
                    static_cast<size_t>(carry_hi_msb),
3135
22.4k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
22.4k
            }
3137
22.4k
        }
3138
22.4k
    }
3139
22.4k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
Line
Count
Source
2608
2.23k
{
2609
2.23k
    ASSERT(input_left.size() == input_right.size());
2610
2.23k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
2.23k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
2.23k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
2.23k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
7.01k
    for (auto& el : input_left) {
2617
7.01k
        el.sanity_check();
2618
7.01k
    }
2619
7.01k
    for (auto& el : input_right) {
2620
7.01k
        el.sanity_check();
2621
7.01k
    }
2622
3.19k
    for (auto& el : to_add) {
2623
3.19k
        el.sanity_check();
2624
3.19k
    }
2625
2.23k
    input_quotient.sanity_check();
2626
2.23k
    for (auto& el : input_remainders) {
2627
2.23k
        el.sanity_check();
2628
2.23k
    }
2629
2.23k
    std::vector<bigfield> remainders(input_remainders);
2630
2.23k
    std::vector<bigfield> left(input_left);
2631
2.23k
    std::vector<bigfield> right(input_right);
2632
2.23k
    bigfield quotient = input_quotient;
2633
2.23k
    const size_t num_multiplications = input_left.size();
2634
2635
2.23k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
2.23k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
2.23k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
2.23k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
2.23k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
2.23k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
2.23k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
2.23k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
2.23k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
2.23k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
2.23k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
2.23k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
2.23k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
2.23k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
2.23k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
2.23k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
2.23k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
2.23k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
2.23k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
2.23k
    uint512_t max_lo = 0;
2665
2.23k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
2.23k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
2.23k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
2.23k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
2.23k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
2.23k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
2.23k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
2.23k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
2.23k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
2.23k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
2.23k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
2.23k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
2.23k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
2.23k
    uint256_t borrow_lo_value(0);
2687
2.23k
    for (const auto& remainder : input_remainders) {
2688
2.23k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
2.23k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
2.23k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
2.23k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
2.23k
    }
2694
2.23k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
2.23k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
2.23k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
2.23k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
2.23k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
2.23k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
2.23k
    uint512_t max_a0(0);
2706
2.23k
    uint512_t max_a1(0);
2707
5.42k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
3.19k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
3.19k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
3.19k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
3.19k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
3.19k
    }
2713
2.23k
    max_lo += max_a0;
2714
2.23k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
9.24k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
7.01k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
7.01k
        max_lo += product_lo;
2720
7.01k
        max_hi += product_hi;
2721
7.01k
    }
2722
2723
2.23k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
2.23k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
2.23k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
2.23k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
2.23k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
1.59k
        ++max_lo_bits;
2733
1.59k
    }
2734
2.23k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
1.59k
        ++max_hi_bits;
2736
1.59k
    }
2737
2738
2.23k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
2.23k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
2.23k
            bigfield output(input);
2744
2.23k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
2.23k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
2.23k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
2.23k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
2.23k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
2.23k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
2.23k
            output.context = ctx;
2755
2.23k
            return output;
2756
2.23k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
2.23k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
2.23k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
2.23k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
9.24k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
7.01k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
7.01k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
7.01k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
7.01k
            if (i > 0 && right[i].is_constant()) {
2783
4
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
4
            }
2785
2786
7.01k
            if (i > 0) {
2787
4.77k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
4.77k
                    {
2789
4.77k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
4.77k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
4.77k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
4.77k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
4.77k
                    },
2794
4.77k
                    {
2795
4.77k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
4.77k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
4.77k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
4.77k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
4.77k
                    },
2800
4.77k
                    {
2801
4.77k
                        ctx->zero_idx,
2802
4.77k
                        ctx->zero_idx,
2803
4.77k
                        ctx->zero_idx,
2804
4.77k
                        ctx->zero_idx,
2805
4.77k
                    },
2806
4.77k
                    {
2807
4.77k
                        ctx->zero_idx,
2808
4.77k
                        ctx->zero_idx,
2809
4.77k
                        ctx->zero_idx,
2810
4.77k
                        ctx->zero_idx,
2811
4.77k
                    },
2812
4.77k
                    { 0, 0, 0, 0 },
2813
4.77k
                    modulus,
2814
4.77k
                };
2815
2816
4.77k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
4.77k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
4.77k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
4.77k
                limb_0_accumulator.emplace_back(-lo_2);
2822
4.77k
                limb_2_accumulator.emplace_back(-hi_2);
2823
4.77k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
4.77k
            }
2825
7.01k
        }
2826
2.23k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
2.23k
        bool no_remainders = remainders.size() == 0;
2831
2.23k
        if (!no_remainders) {
2832
2.23k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
2.23k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
2.23k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
2.23k
        }
2836
2.23k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
3.19k
        for (const auto& add : to_add) {
2844
3.19k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
3.19k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
3.19k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
3.19k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
3.19k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
3.19k
        }
2850
2851
2.23k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
2.23k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
2.23k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
2.23k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
2.23k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
2.23k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
2.23k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
2.23k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
2.23k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
2.23k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
2.23k
        field_t<Builder> remainder_limbs[4]{
2872
2.23k
            accumulated_lo,
2873
2.23k
            remainder1,
2874
2.23k
            accumulated_hi,
2875
2.23k
            remainder3,
2876
2.23k
        };
2877
2.23k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
2.23k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
2.23k
            {
2881
2.23k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
2.23k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
2.23k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
2.23k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
2.23k
            },
2886
2.23k
            {
2887
2.23k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
2.23k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
2.23k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
2.23k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
2.23k
            },
2892
2.23k
            {
2893
2.23k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
2.23k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
2.23k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
2.23k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
2.23k
            },
2898
2.23k
            {
2899
2.23k
                remainder_limbs[0].get_normalized_witness_index(),
2900
2.23k
                remainder_limbs[1].get_normalized_witness_index(),
2901
2.23k
                remainder_limbs[2].get_normalized_witness_index(),
2902
2.23k
                remainder_limbs[3].get_normalized_witness_index(),
2903
2.23k
            },
2904
2.23k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
2.23k
            modulus,
2906
2.23k
        };
2907
2908
2.23k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
2.23k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
2.23k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
2.23k
                                                       right[0].prime_basis_limb,
2914
2.23k
                                                       quotient.prime_basis_limb * neg_prime,
2915
2.23k
                                                       -remainder_prime_limb);
2916
2917
2.23k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
2.23k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
2.23k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
2.23k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
2.23k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
2.23k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
2.23k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
2.23k
        } else {
2938
2.23k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
2.23k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
2.23k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
2.23k
    } else {
2953
2.23k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
2.23k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
2.23k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
2.23k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
2.23k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
2.23k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
2.23k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
2.23k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
2.23k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
2.23k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
2.23k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
2.23k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
2.23k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
2.23k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
2.23k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
2.23k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
2.23k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
2.23k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
2.23k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
2.23k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
2.23k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
2.23k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
2.23k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
2.23k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
2.23k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
2.23k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
2.23k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
2.23k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
2.23k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
2.23k
            limb_0_accumulator.emplace_back(-lo_2);
3006
2.23k
            limb_2_accumulator.emplace_back(-hi_2);
3007
2.23k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
2.23k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
2.23k
        bool no_remainders = remainders.size() == 0;
3018
2.23k
        if (!no_remainders) {
3019
2.23k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
2.23k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
2.23k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
2.23k
        }
3023
2.23k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
2.23k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
2.23k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
2.23k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
2.23k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
2.23k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
2.23k
        }
3030
2.23k
        for (const auto& add : to_add) {
3031
2.23k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
2.23k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
2.23k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
2.23k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
2.23k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
2.23k
        }
3037
3038
2.23k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
2.23k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
2.23k
        if (accumulated_lo.is_constant()) {
3041
2.23k
            accumulated_lo =
3042
2.23k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
2.23k
        }
3044
2.23k
        if (accumulated_hi.is_constant()) {
3045
2.23k
            accumulated_hi =
3046
2.23k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
2.23k
        }
3048
2.23k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
2.23k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
2.23k
        if (remainder1.is_constant()) {
3051
2.23k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
2.23k
        }
3053
2.23k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
2.23k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
2.23k
        if (remainder3.is_constant()) {
3056
2.23k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
2.23k
        }
3058
2.23k
        field_t<Builder> remainder_limbs[4]{
3059
2.23k
            accumulated_lo,
3060
2.23k
            remainder1,
3061
2.23k
            accumulated_hi,
3062
2.23k
            remainder3,
3063
2.23k
        };
3064
2.23k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
2.23k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
2.23k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
2.23k
        const field_t r2 = c0.add_two(c1, c2);
3077
2.23k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
2.23k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
2.23k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
2.23k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
2.23k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
2.23k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
2.23k
        carry_lo += borrow_lo;
3086
2.23k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
2.23k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
2.23k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
2.23k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
2.23k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
2.23k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
2.23k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
2.23k
        field_t<Builder>::evaluate_polynomial_identity(
3099
2.23k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
2.23k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
2.23k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
2.23k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
2.23k
        if constexpr (HasPlookup<Builder>) {
3107
2.23k
            carry_lo = carry_lo.normalize();
3108
2.23k
            carry_hi = carry_hi.normalize();
3109
2.23k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
2.23k
                                              static_cast<size_t>(carry_lo_msb));
3111
2.23k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
2.23k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
2.23k
        } else {
3115
2.23k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
2.23k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
2.23k
                carry_combined = carry_combined.normalize();
3118
2.23k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
2.23k
                    carry_combined.get_normalized_witness_index(),
3120
2.23k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
2.23k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
2.23k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
2.23k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
2.23k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
2.23k
            } else {
3126
2.23k
                carry_lo = carry_lo.normalize();
3127
2.23k
                carry_hi = carry_hi.normalize();
3128
2.23k
                ctx->decompose_into_base4_accumulators(
3129
2.23k
                    carry_lo.get_normalized_witness_index(),
3130
2.23k
                    static_cast<size_t>(carry_lo_msb),
3131
2.23k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
2.23k
                ctx->decompose_into_base4_accumulators(
3133
2.23k
                    carry_hi.get_normalized_witness_index(),
3134
2.23k
                    static_cast<size_t>(carry_hi_msb),
3135
2.23k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
2.23k
            }
3137
2.23k
        }
3138
2.23k
    }
3139
2.23k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
Line
Count
Source
2608
1.78k
{
2609
1.78k
    ASSERT(input_left.size() == input_right.size());
2610
1.78k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
1.78k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
1.78k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
1.78k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
5.60k
    for (auto& el : input_left) {
2617
5.60k
        el.sanity_check();
2618
5.60k
    }
2619
5.60k
    for (auto& el : input_right) {
2620
5.60k
        el.sanity_check();
2621
5.60k
    }
2622
2.55k
    for (auto& el : to_add) {
2623
2.55k
        el.sanity_check();
2624
2.55k
    }
2625
1.78k
    input_quotient.sanity_check();
2626
1.78k
    for (auto& el : input_remainders) {
2627
1.78k
        el.sanity_check();
2628
1.78k
    }
2629
1.78k
    std::vector<bigfield> remainders(input_remainders);
2630
1.78k
    std::vector<bigfield> left(input_left);
2631
1.78k
    std::vector<bigfield> right(input_right);
2632
1.78k
    bigfield quotient = input_quotient;
2633
1.78k
    const size_t num_multiplications = input_left.size();
2634
2635
1.78k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
1.78k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
1.78k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
1.78k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
1.78k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
1.78k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
1.78k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
1.78k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
1.78k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
1.78k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
1.78k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
1.78k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
1.78k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
1.78k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
1.78k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
1.78k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
1.78k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
1.78k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
1.78k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
1.78k
    uint512_t max_lo = 0;
2665
1.78k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
1.78k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
1.78k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
1.78k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
1.78k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
1.78k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
1.78k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
1.78k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
1.78k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
1.78k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
1.78k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
1.78k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
1.78k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
1.78k
    uint256_t borrow_lo_value(0);
2687
1.78k
    for (const auto& remainder : input_remainders) {
2688
1.78k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
1.78k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
1.78k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
1.78k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
1.78k
    }
2694
1.78k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
1.78k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
1.78k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
1.78k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
1.78k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
1.78k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
1.78k
    uint512_t max_a0(0);
2706
1.78k
    uint512_t max_a1(0);
2707
4.34k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
2.55k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
2.55k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
2.55k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
2.55k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
2.55k
    }
2713
1.78k
    max_lo += max_a0;
2714
1.78k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
7.39k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
5.60k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
5.60k
        max_lo += product_lo;
2720
5.60k
        max_hi += product_hi;
2721
5.60k
    }
2722
2723
1.78k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
1.78k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
1.78k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
1.78k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
1.78k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
1.27k
        ++max_lo_bits;
2733
1.27k
    }
2734
1.78k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
1.27k
        ++max_hi_bits;
2736
1.27k
    }
2737
2738
1.78k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
1.78k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
1.78k
            bigfield output(input);
2744
1.78k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
1.78k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
1.78k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
1.78k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
1.78k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
1.78k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
1.78k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
1.78k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
1.78k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
1.78k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
1.78k
            output.context = ctx;
2755
1.78k
            return output;
2756
1.78k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
1.78k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
1.78k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
1.78k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
7.39k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
5.60k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
5.60k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
5.60k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
5.60k
            if (i > 0 && right[i].is_constant()) {
2783
4
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
4
            }
2785
2786
5.60k
            if (i > 0) {
2787
3.82k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
3.82k
                    {
2789
3.82k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
3.82k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
3.82k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
3.82k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
3.82k
                    },
2794
3.82k
                    {
2795
3.82k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
3.82k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
3.82k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
3.82k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
3.82k
                    },
2800
3.82k
                    {
2801
3.82k
                        ctx->zero_idx,
2802
3.82k
                        ctx->zero_idx,
2803
3.82k
                        ctx->zero_idx,
2804
3.82k
                        ctx->zero_idx,
2805
3.82k
                    },
2806
3.82k
                    {
2807
3.82k
                        ctx->zero_idx,
2808
3.82k
                        ctx->zero_idx,
2809
3.82k
                        ctx->zero_idx,
2810
3.82k
                        ctx->zero_idx,
2811
3.82k
                    },
2812
3.82k
                    { 0, 0, 0, 0 },
2813
3.82k
                    modulus,
2814
3.82k
                };
2815
2816
3.82k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
3.82k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
3.82k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
3.82k
                limb_0_accumulator.emplace_back(-lo_2);
2822
3.82k
                limb_2_accumulator.emplace_back(-hi_2);
2823
3.82k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
3.82k
            }
2825
5.60k
        }
2826
1.78k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
1.78k
        bool no_remainders = remainders.size() == 0;
2831
1.78k
        if (!no_remainders) {
2832
1.78k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
1.78k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
1.78k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
1.78k
        }
2836
1.78k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
2.55k
        for (const auto& add : to_add) {
2844
2.55k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
2.55k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
2.55k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
2.55k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
2.55k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
2.55k
        }
2850
2851
1.78k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
1.78k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
1.78k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
1.78k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
1.78k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
1.78k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
1.78k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
1.78k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
1.78k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
1.78k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
1.78k
        field_t<Builder> remainder_limbs[4]{
2872
1.78k
            accumulated_lo,
2873
1.78k
            remainder1,
2874
1.78k
            accumulated_hi,
2875
1.78k
            remainder3,
2876
1.78k
        };
2877
1.78k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
1.78k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
1.78k
            {
2881
1.78k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
1.78k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
1.78k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
1.78k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
1.78k
            },
2886
1.78k
            {
2887
1.78k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
1.78k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
1.78k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
1.78k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
1.78k
            },
2892
1.78k
            {
2893
1.78k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
1.78k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
1.78k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
1.78k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
1.78k
            },
2898
1.78k
            {
2899
1.78k
                remainder_limbs[0].get_normalized_witness_index(),
2900
1.78k
                remainder_limbs[1].get_normalized_witness_index(),
2901
1.78k
                remainder_limbs[2].get_normalized_witness_index(),
2902
1.78k
                remainder_limbs[3].get_normalized_witness_index(),
2903
1.78k
            },
2904
1.78k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
1.78k
            modulus,
2906
1.78k
        };
2907
2908
1.78k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
1.78k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
1.78k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
1.78k
                                                       right[0].prime_basis_limb,
2914
1.78k
                                                       quotient.prime_basis_limb * neg_prime,
2915
1.78k
                                                       -remainder_prime_limb);
2916
2917
1.78k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
1.78k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
1.78k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
1.78k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
1.78k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
1.78k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
1.78k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
1.78k
        } else {
2938
1.78k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
1.78k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
1.78k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
1.78k
    } else {
2953
1.78k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
1.78k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
1.78k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
1.78k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
1.78k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
1.78k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
1.78k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
1.78k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
1.78k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
1.78k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
1.78k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
1.78k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
1.78k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
1.78k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
1.78k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
1.78k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
1.78k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
1.78k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
1.78k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
1.78k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
1.78k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
1.78k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
1.78k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
1.78k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
1.78k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
1.78k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
1.78k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
1.78k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
1.78k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
1.78k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
1.78k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
1.78k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
1.78k
            limb_0_accumulator.emplace_back(-lo_2);
3006
1.78k
            limb_2_accumulator.emplace_back(-hi_2);
3007
1.78k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
1.78k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
1.78k
        bool no_remainders = remainders.size() == 0;
3018
1.78k
        if (!no_remainders) {
3019
1.78k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
1.78k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
1.78k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
1.78k
        }
3023
1.78k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
1.78k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
1.78k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
1.78k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
1.78k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
1.78k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
1.78k
        }
3030
1.78k
        for (const auto& add : to_add) {
3031
1.78k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
1.78k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
1.78k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
1.78k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
1.78k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
1.78k
        }
3037
3038
1.78k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
1.78k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
1.78k
        if (accumulated_lo.is_constant()) {
3041
1.78k
            accumulated_lo =
3042
1.78k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
1.78k
        }
3044
1.78k
        if (accumulated_hi.is_constant()) {
3045
1.78k
            accumulated_hi =
3046
1.78k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
1.78k
        }
3048
1.78k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
1.78k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
1.78k
        if (remainder1.is_constant()) {
3051
1.78k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
1.78k
        }
3053
1.78k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
1.78k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
1.78k
        if (remainder3.is_constant()) {
3056
1.78k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
1.78k
        }
3058
1.78k
        field_t<Builder> remainder_limbs[4]{
3059
1.78k
            accumulated_lo,
3060
1.78k
            remainder1,
3061
1.78k
            accumulated_hi,
3062
1.78k
            remainder3,
3063
1.78k
        };
3064
1.78k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
1.78k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
1.78k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
1.78k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
1.78k
        const field_t r2 = c0.add_two(c1, c2);
3077
1.78k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
1.78k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
1.78k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
1.78k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
1.78k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
1.78k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
1.78k
        carry_lo += borrow_lo;
3086
1.78k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
1.78k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
1.78k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
1.78k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
1.78k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
1.78k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
1.78k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
1.78k
        field_t<Builder>::evaluate_polynomial_identity(
3099
1.78k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
1.78k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
1.78k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
1.78k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
1.78k
        if constexpr (HasPlookup<Builder>) {
3107
1.78k
            carry_lo = carry_lo.normalize();
3108
1.78k
            carry_hi = carry_hi.normalize();
3109
1.78k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
1.78k
                                              static_cast<size_t>(carry_lo_msb));
3111
1.78k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
1.78k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
1.78k
        } else {
3115
1.78k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
1.78k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
1.78k
                carry_combined = carry_combined.normalize();
3118
1.78k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
1.78k
                    carry_combined.get_normalized_witness_index(),
3120
1.78k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
1.78k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
1.78k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
1.78k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
1.78k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
1.78k
            } else {
3126
1.78k
                carry_lo = carry_lo.normalize();
3127
1.78k
                carry_hi = carry_hi.normalize();
3128
1.78k
                ctx->decompose_into_base4_accumulators(
3129
1.78k
                    carry_lo.get_normalized_witness_index(),
3130
1.78k
                    static_cast<size_t>(carry_lo_msb),
3131
1.78k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
1.78k
                ctx->decompose_into_base4_accumulators(
3133
1.78k
                    carry_hi.get_normalized_witness_index(),
3134
1.78k
                    static_cast<size_t>(carry_hi_msb),
3135
1.78k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
1.78k
            }
3137
1.78k
        }
3138
1.78k
    }
3139
1.78k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
3140
3141
template <typename Builder, typename T>
3142
void bigfield<Builder, T>::unsafe_evaluate_square_add(const bigfield& left,
3143
                                                      const std::vector<bigfield>& to_add,
3144
                                                      const bigfield& quotient,
3145
                                                      const bigfield& remainder)
3146
331k
{
3147
331k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
331k
    if (HasPlookup<Builder>) {
3150
331k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
331k
        return;
3152
331k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Line
Count
Source
3146
311k
{
3147
311k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
311k
    if (HasPlookup<Builder>) {
3150
311k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
311k
        return;
3152
311k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS8_RKSt6vectorIS8_SaIS8_EESA_SA_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
Line
Count
Source
3146
1.01k
{
3147
1.01k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
1.01k
    if (HasPlookup<Builder>) {
3150
1.01k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
1.01k
        return;
3152
1.01k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
Line
Count
Source
3146
16.5k
{
3147
16.5k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
16.5k
    if (HasPlookup<Builder>) {
3150
16.5k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
16.5k
        return;
3152
16.5k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
Line
Count
Source
3146
1.31k
{
3147
1.31k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
1.31k
    if (HasPlookup<Builder>) {
3150
1.31k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
1.31k
        return;
3152
1.31k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
Line
Count
Source
3146
1.04k
{
3147
1.04k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
1.04k
    if (HasPlookup<Builder>) {
3150
1.04k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
1.04k
        return;
3152
1.04k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS8_RKSt6vectorIS8_SaIS8_EESA_SA_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
3308
3309
template <typename Builder, typename T>
3310
std::pair<uint512_t, uint512_t> bigfield<Builder, T>::compute_quotient_remainder_values(
3311
    const bigfield& a, const bigfield& b, const std::vector<bigfield>& to_add)
3312
209k
{
3313
209k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
0
    uint512_t add_values(0);
3316
0
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
0
    const uint1024_t left(a.get_value());
3322
0
    const uint1024_t right(b.get_value());
3323
0
    const uint1024_t add_right(add_values);
3324
0
    const uint1024_t modulus(target_basis.modulus);
3325
3326
0
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
0
    return { quotient_1024.lo, remainder_1024.lo };
3329
209k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
3312
203k
{
3313
203k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
203k
    uint512_t add_values(0);
3316
203k
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
203k
    const uint1024_t left(a.get_value());
3322
203k
    const uint1024_t right(b.get_value());
3323
203k
    const uint1024_t add_right(add_values);
3324
203k
    const uint1024_t modulus(target_basis.modulus);
3325
3326
203k
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
203k
    return { quotient_1024.lo, remainder_1024.lo };
3329
203k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
3312
38
{
3313
38
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
38
    uint512_t add_values(0);
3316
38
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
38
    const uint1024_t left(a.get_value());
3322
38
    const uint1024_t right(b.get_value());
3323
38
    const uint1024_t add_right(add_values);
3324
38
    const uint1024_t modulus(target_basis.modulus);
3325
3326
38
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
38
    return { quotient_1024.lo, remainder_1024.lo };
3329
38
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS8_SA_RKSt6vectorIS8_SaIS8_EE
Line
Count
Source
3312
20
{
3313
20
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
20
    uint512_t add_values(0);
3316
20
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
20
    const uint1024_t left(a.get_value());
3322
20
    const uint1024_t right(b.get_value());
3323
20
    const uint1024_t add_right(add_values);
3324
20
    const uint1024_t modulus(target_basis.modulus);
3325
3326
20
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
20
    return { quotient_1024.lo, remainder_1024.lo };
3329
20
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
3312
255
{
3313
255
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
255
    uint512_t add_values(0);
3316
255
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
255
    const uint1024_t left(a.get_value());
3322
255
    const uint1024_t right(b.get_value());
3323
255
    const uint1024_t add_right(add_values);
3324
255
    const uint1024_t modulus(target_basis.modulus);
3325
3326
255
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
255
    return { quotient_1024.lo, remainder_1024.lo };
3329
255
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
3312
1
{
3313
1
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
1
    uint512_t add_values(0);
3316
1
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
1
    const uint1024_t left(a.get_value());
3322
1
    const uint1024_t right(b.get_value());
3323
1
    const uint1024_t add_right(add_values);
3324
1
    const uint1024_t modulus(target_basis.modulus);
3325
3326
1
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
1
    return { quotient_1024.lo, remainder_1024.lo };
3329
1
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
3312
4.90k
{
3313
4.90k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
4.90k
    uint512_t add_values(0);
3316
4.90k
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
4.90k
    const uint1024_t left(a.get_value());
3322
4.90k
    const uint1024_t right(b.get_value());
3323
4.90k
    const uint1024_t add_right(add_values);
3324
4.90k
    const uint1024_t modulus(target_basis.modulus);
3325
3326
4.90k
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
4.90k
    return { quotient_1024.lo, remainder_1024.lo };
3329
4.90k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
3312
51
{
3313
51
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
51
    uint512_t add_values(0);
3316
51
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
51
    const uint1024_t left(a.get_value());
3322
51
    const uint1024_t right(b.get_value());
3323
51
    const uint1024_t add_right(add_values);
3324
51
    const uint1024_t modulus(target_basis.modulus);
3325
3326
51
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
51
    return { quotient_1024.lo, remainder_1024.lo };
3329
51
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
3312
40
{
3313
40
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
40
    uint512_t add_values(0);
3316
40
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
40
    const uint1024_t left(a.get_value());
3322
40
    const uint1024_t right(b.get_value());
3323
40
    const uint1024_t add_right(add_values);
3324
40
    const uint1024_t modulus(target_basis.modulus);
3325
3326
40
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
40
    return { quotient_1024.lo, remainder_1024.lo };
3329
40
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS8_SA_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
3330
3331
template <typename Builder, typename T>
3332
uint512_t bigfield<Builder, T>::compute_maximum_quotient_value(const std::vector<uint512_t>& as,
3333
                                                               const std::vector<uint512_t>& bs,
3334
                                                               const std::vector<uint512_t>& to_add)
3335
1.06M
{
3336
1.06M
    ASSERT(as.size() == bs.size());
3337
1.06M
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
0
    uint512_t add_values(0);
3340
1.47M
    for (const auto& add_element : to_add) {
3341
1.47M
        add_values += add_element;
3342
1.47M
    }
3343
0
    uint1024_t product_sum(0);
3344
2.53M
    for (size_t i = 0; i < as.size(); i++) {
3345
1.46M
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
1.46M
    }
3347
0
    const uint1024_t add_right(add_values);
3348
0
    const uint1024_t modulus(target_basis.modulus);
3349
3350
0
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
0
    return quotient_1024.lo;
3353
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Line
Count
Source
3335
986k
{
3336
986k
    ASSERT(as.size() == bs.size());
3337
986k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
986k
    uint512_t add_values(0);
3340
1.36M
    for (const auto& add_element : to_add) {
3341
1.36M
        add_values += add_element;
3342
1.36M
    }
3343
986k
    uint1024_t product_sum(0);
3344
2.32M
    for (size_t i = 0; i < as.size(); i++) {
3345
1.34M
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
1.34M
    }
3347
986k
    const uint1024_t add_right(add_values);
3348
986k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
986k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
986k
    return quotient_1024.lo;
3353
986k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Line
Count
Source
3335
38
{
3336
38
    ASSERT(as.size() == bs.size());
3337
38
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
38
    uint512_t add_values(0);
3340
38
    for (const auto& add_element : to_add) {
3341
0
        add_values += add_element;
3342
0
    }
3343
38
    uint1024_t product_sum(0);
3344
76
    for (size_t i = 0; i < as.size(); i++) {
3345
38
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
38
    }
3347
38
    const uint1024_t add_right(add_values);
3348
38
    const uint1024_t modulus(target_basis.modulus);
3349
3350
38
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
38
    return quotient_1024.lo;
3353
38
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_SH_
Line
Count
Source
3335
16
{
3336
16
    ASSERT(as.size() == bs.size());
3337
16
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
16
    uint512_t add_values(0);
3340
16
    for (const auto& add_element : to_add) {
3341
0
        add_values += add_element;
3342
0
    }
3343
16
    uint1024_t product_sum(0);
3344
32
    for (size_t i = 0; i < as.size(); i++) {
3345
16
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
16
    }
3347
16
    const uint1024_t add_right(add_values);
3348
16
    const uint1024_t modulus(target_basis.modulus);
3349
3350
16
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
16
    return quotient_1024.lo;
3353
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
4.01k
{
3336
4.01k
    ASSERT(as.size() == bs.size());
3337
4.01k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
4.01k
    uint512_t add_values(0);
3340
5.10k
    for (const auto& add_element : to_add) {
3341
5.10k
        add_values += add_element;
3342
5.10k
    }
3343
4.01k
    uint1024_t product_sum(0);
3344
9.88k
    for (size_t i = 0; i < as.size(); i++) {
3345
5.87k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
5.87k
    }
3347
4.01k
    const uint1024_t add_right(add_values);
3348
4.01k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
4.01k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
4.01k
    return quotient_1024.lo;
3353
4.01k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
27
{
3336
27
    ASSERT(as.size() == bs.size());
3337
27
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
27
    uint512_t add_values(0);
3340
27
    for (const auto& add_element : to_add) {
3341
26
        add_values += add_element;
3342
26
    }
3343
27
    uint1024_t product_sum(0);
3344
54
    for (size_t i = 0; i < as.size(); i++) {
3345
27
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
27
    }
3347
27
    const uint1024_t add_right(add_values);
3348
27
    const uint1024_t modulus(target_basis.modulus);
3349
3350
27
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
27
    return quotient_1024.lo;
3353
27
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Line
Count
Source
3335
68.4k
{
3336
68.4k
    ASSERT(as.size() == bs.size());
3337
68.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
68.4k
    uint512_t add_values(0);
3340
90.7k
    for (const auto& add_element : to_add) {
3341
90.7k
        add_values += add_element;
3342
90.7k
    }
3343
68.4k
    uint1024_t product_sum(0);
3344
170k
    for (size_t i = 0; i < as.size(); i++) {
3345
101k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
101k
    }
3347
68.4k
    const uint1024_t add_right(add_values);
3348
68.4k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
68.4k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
68.4k
    return quotient_1024.lo;
3353
68.4k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Line
Count
Source
3335
456
{
3336
456
    ASSERT(as.size() == bs.size());
3337
456
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
456
    uint512_t add_values(0);
3340
456
    for (const auto& add_element : to_add) {
3341
456
        add_values += add_element;
3342
456
    }
3343
456
    uint1024_t product_sum(0);
3344
912
    for (size_t i = 0; i < as.size(); i++) {
3345
456
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
456
    }
3347
456
    const uint1024_t add_right(add_values);
3348
456
    const uint1024_t modulus(target_basis.modulus);
3349
3350
456
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
456
    return quotient_1024.lo;
3353
456
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
5.56k
{
3336
5.56k
    ASSERT(as.size() == bs.size());
3337
5.56k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
5.56k
    uint512_t add_values(0);
3340
9.04k
    for (const auto& add_element : to_add) {
3341
9.04k
        add_values += add_element;
3342
9.04k
    }
3343
5.56k
    uint1024_t product_sum(0);
3344
15.9k
    for (size_t i = 0; i < as.size(); i++) {
3345
10.3k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
10.3k
    }
3347
5.56k
    const uint1024_t add_right(add_values);
3348
5.56k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
5.56k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
5.56k
    return quotient_1024.lo;
3353
5.56k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
10
{
3336
10
    ASSERT(as.size() == bs.size());
3337
10
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
10
    uint512_t add_values(0);
3340
10
    for (const auto& add_element : to_add) {
3341
10
        add_values += add_element;
3342
10
    }
3343
10
    uint1024_t product_sum(0);
3344
20
    for (size_t i = 0; i < as.size(); i++) {
3345
10
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
10
    }
3347
10
    const uint1024_t add_right(add_values);
3348
10
    const uint1024_t modulus(target_basis.modulus);
3349
3350
10
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
10
    return quotient_1024.lo;
3353
10
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Line
Count
Source
3335
4.45k
{
3336
4.45k
    ASSERT(as.size() == bs.size());
3337
4.45k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
4.45k
    uint512_t add_values(0);
3340
7.23k
    for (const auto& add_element : to_add) {
3341
7.23k
        add_values += add_element;
3342
7.23k
    }
3343
4.45k
    uint1024_t product_sum(0);
3344
12.7k
    for (size_t i = 0; i < as.size(); i++) {
3345
8.27k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
8.27k
    }
3347
4.45k
    const uint1024_t add_right(add_values);
3348
4.45k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
4.45k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
4.45k
    return quotient_1024.lo;
3353
4.45k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Line
Count
Source
3335
8
{
3336
8
    ASSERT(as.size() == bs.size());
3337
8
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
8
    uint512_t add_values(0);
3340
8
    for (const auto& add_element : to_add) {
3341
8
        add_values += add_element;
3342
8
    }
3343
8
    uint1024_t product_sum(0);
3344
16
    for (size_t i = 0; i < as.size(); i++) {
3345
8
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
8
    }
3347
8
    const uint1024_t add_right(add_values);
3348
8
    const uint1024_t modulus(target_basis.modulus);
3349
3350
8
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
8
    return quotient_1024.lo;
3353
8
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_SH_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
3354
template <typename Builder, typename T>
3355
std::pair<bool, size_t> bigfield<Builder, T>::get_quotient_reduction_info(const std::vector<uint512_t>& as_max,
3356
                                                                          const std::vector<uint512_t>& bs_max,
3357
                                                                          const std::vector<bigfield>& to_add,
3358
                                                                          const std::vector<uint1024_t>& remainders_max)
3359
1.06M
{
3360
1.06M
    ASSERT(as_max.size() == bs_max.size());
3361
3362
1.06M
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
1.06M
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
1.06M
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
1.06M
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
1.06M
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
1.06M
    std::vector<uint512_t> to_add_max;
3372
1.47M
    for (auto& added_element : to_add) {
3373
1.47M
        to_add_max.push_back(added_element.get_maximum_value());
3374
1.47M
    }
3375
    // Get maximum value of quotient
3376
1.06M
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
1.06M
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
5
        return std::pair<bool, size_t>(true, 0);
3381
5
    }
3382
1.06M
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
1.06M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Line
Count
Source
3359
986k
{
3360
986k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
986k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
986k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
986k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
986k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
986k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
986k
    std::vector<uint512_t> to_add_max;
3372
1.36M
    for (auto& added_element : to_add) {
3373
1.36M
        to_add_max.push_back(added_element.get_maximum_value());
3374
1.36M
    }
3375
    // Get maximum value of quotient
3376
986k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
986k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
5
        return std::pair<bool, size_t>(true, 0);
3381
5
    }
3382
986k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
986k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Line
Count
Source
3359
38
{
3360
38
    ASSERT(as_max.size() == bs_max.size());
3361
3362
38
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
38
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
38
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
38
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
38
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
38
    std::vector<uint512_t> to_add_max;
3372
38
    for (auto& added_element : to_add) {
3373
0
        to_add_max.push_back(added_element.get_maximum_value());
3374
0
    }
3375
    // Get maximum value of quotient
3376
38
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
38
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
38
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
38
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_RKS9_IS8_SaIS8_EERKS9_INSB_ISD_EESaISM_EE
Line
Count
Source
3359
16
{
3360
16
    ASSERT(as_max.size() == bs_max.size());
3361
3362
16
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
16
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
16
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
16
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
16
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
16
    std::vector<uint512_t> to_add_max;
3372
16
    for (auto& added_element : to_add) {
3373
0
        to_add_max.push_back(added_element.get_maximum_value());
3374
0
    }
3375
    // Get maximum value of quotient
3376
16
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
16
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
16
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
4.01k
{
3360
4.01k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
4.01k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
4.01k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
4.01k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
4.01k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
4.01k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
4.01k
    std::vector<uint512_t> to_add_max;
3372
5.10k
    for (auto& added_element : to_add) {
3373
5.10k
        to_add_max.push_back(added_element.get_maximum_value());
3374
5.10k
    }
3375
    // Get maximum value of quotient
3376
4.01k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
4.01k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
4.01k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
4.01k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
27
{
3360
27
    ASSERT(as_max.size() == bs_max.size());
3361
3362
27
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
27
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
27
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
27
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
27
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
27
    std::vector<uint512_t> to_add_max;
3372
27
    for (auto& added_element : to_add) {
3373
26
        to_add_max.push_back(added_element.get_maximum_value());
3374
26
    }
3375
    // Get maximum value of quotient
3376
27
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
27
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
27
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
27
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Line
Count
Source
3359
68.4k
{
3360
68.4k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
68.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
68.4k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
68.4k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
68.4k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
68.4k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
68.4k
    std::vector<uint512_t> to_add_max;
3372
90.7k
    for (auto& added_element : to_add) {
3373
90.7k
        to_add_max.push_back(added_element.get_maximum_value());
3374
90.7k
    }
3375
    // Get maximum value of quotient
3376
68.4k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
68.4k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
68.4k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
68.4k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Line
Count
Source
3359
456
{
3360
456
    ASSERT(as_max.size() == bs_max.size());
3361
3362
456
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
456
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
456
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
456
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
456
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
456
    std::vector<uint512_t> to_add_max;
3372
456
    for (auto& added_element : to_add) {
3373
456
        to_add_max.push_back(added_element.get_maximum_value());
3374
456
    }
3375
    // Get maximum value of quotient
3376
456
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
456
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
456
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
456
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
5.56k
{
3360
5.56k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
5.56k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
5.56k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
5.56k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
5.56k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
5.56k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
5.56k
    std::vector<uint512_t> to_add_max;
3372
9.04k
    for (auto& added_element : to_add) {
3373
9.04k
        to_add_max.push_back(added_element.get_maximum_value());
3374
9.04k
    }
3375
    // Get maximum value of quotient
3376
5.56k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
5.56k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
5.56k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
5.56k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
10
{
3360
10
    ASSERT(as_max.size() == bs_max.size());
3361
3362
10
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
10
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
10
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
10
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
10
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
10
    std::vector<uint512_t> to_add_max;
3372
10
    for (auto& added_element : to_add) {
3373
10
        to_add_max.push_back(added_element.get_maximum_value());
3374
10
    }
3375
    // Get maximum value of quotient
3376
10
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
10
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
10
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
10
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Line
Count
Source
3359
4.45k
{
3360
4.45k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
4.45k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
4.45k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
4.45k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
4.45k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
4.45k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
4.45k
    std::vector<uint512_t> to_add_max;
3372
7.23k
    for (auto& added_element : to_add) {
3373
7.23k
        to_add_max.push_back(added_element.get_maximum_value());
3374
7.23k
    }
3375
    // Get maximum value of quotient
3376
4.45k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
4.45k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
4.45k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
4.45k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Line
Count
Source
3359
8
{
3360
8
    ASSERT(as_max.size() == bs_max.size());
3361
3362
8
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
8
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
8
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
8
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
8
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
8
    std::vector<uint512_t> to_add_max;
3372
8
    for (auto& added_element : to_add) {
3373
8
        to_add_max.push_back(added_element.get_maximum_value());
3374
8
    }
3375
    // Get maximum value of quotient
3376
8
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
8
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
8
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
8
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_RKS9_IS8_SaIS8_EERKS9_INSB_ISD_EESaISM_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
3384
3385
} // namespace bb::stdlib